diff options
Diffstat (limited to 'library/src/structure')
| -rw-r--r-- | library/src/structure/heading.rs | 102 | ||||
| -rw-r--r-- | library/src/structure/list.rs | 72 | ||||
| -rw-r--r-- | library/src/structure/table.rs | 39 |
3 files changed, 51 insertions, 162 deletions
diff --git a/library/src/structure/heading.rs b/library/src/structure/heading.rs index fe9b9013..87b522f7 100644 --- a/library/src/structure/heading.rs +++ b/library/src/structure/heading.rs @@ -1,6 +1,6 @@ use typst::font::FontWeight; -use crate::layout::{BlockNode, BlockSpacing}; +use crate::layout::{BlockNode, VNode}; use crate::prelude::*; use crate::text::{TextNode, TextSize}; @@ -16,25 +16,6 @@ pub struct HeadingNode { #[node(Show, Finalize)] impl HeadingNode { - /// Whether the heading appears in the outline. - pub const OUTLINED: bool = true; - /// Whether the heading is numbered. - pub const NUMBERED: bool = true; - - /// The spacing above the heading. - #[property(referenced, shorthand(around))] - pub const ABOVE: Leveled<Option<BlockSpacing>> = Leveled::Mapping(|level| { - let ratio = match level.get() { - 1 => 1.5, - _ => 1.2, - }; - Some(Ratio::new(ratio).into()) - }); - /// The spacing below the heading. - #[property(referenced, shorthand(around))] - pub const BELOW: Leveled<Option<BlockSpacing>> = - Leveled::Value(Some(Ratio::new(0.55).into())); - fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { Ok(Self { body: args.expect("body")?, @@ -65,76 +46,25 @@ impl Show for HeadingNode { impl Finalize for HeadingNode { fn finalize( &self, - world: Tracked<dyn World>, - styles: StyleChain, - mut realized: Content, + _: Tracked<dyn World>, + _: StyleChain, + realized: Content, ) -> SourceResult<Content> { - macro_rules! resolve { - ($key:expr) => { - styles.get($key).resolve(world, self.level)? - }; - } - - let mut map = StyleMap::new(); - map.set(TextNode::SIZE, { - let size = match self.level.get() { - 1 => 1.4, - 2 => 1.2, - _ => 1.0, - }; - TextSize(Em::new(size).into()) + let size = Em::new(match self.level.get() { + 1 => 1.4, + 2 => 1.2, + _ => 1.0, }); - map.set(TextNode::WEIGHT, FontWeight::BOLD); - realized = realized.styled_with_map(map).spaced( - resolve!(Self::ABOVE).resolve(styles), - resolve!(Self::BELOW).resolve(styles), - ); + let above = Em::new(if self.level.get() == 1 { 1.8 } else { 1.44 }); + let below = Em::new(0.66); - Ok(realized) - } -} - -/// Either the value or a closure mapping to the value. -#[derive(Debug, Clone, PartialEq, Hash)] -pub enum Leveled<T> { - /// A bare value. - Value(T), - /// A simple mapping from a heading level to a value. - Mapping(fn(NonZeroUsize) -> T), - /// A closure mapping from a heading level to a value. - Func(Func, Span), -} - -impl<T: Cast + Clone> Leveled<T> { - /// Resolve the value based on the level. - pub fn resolve( - &self, - world: Tracked<dyn World>, - level: NonZeroUsize, - ) -> SourceResult<T> { - Ok(match self { - Self::Value(value) => value.clone(), - Self::Mapping(mapping) => mapping(level), - Self::Func(func, span) => { - let args = Args::new(*span, [Value::Int(level.get() as i64)]); - func.call_detached(world, args)?.cast().at(*span)? - } - }) - } -} - -impl<T: Cast> Cast<Spanned<Value>> for Leveled<T> { - fn is(value: &Spanned<Value>) -> bool { - matches!(&value.v, Value::Func(_)) || T::is(&value.v) - } + let mut map = StyleMap::new(); + map.set(TextNode::SIZE, TextSize(size.into())); + map.set(TextNode::WEIGHT, FontWeight::BOLD); + map.set(BlockNode::ABOVE, VNode::strong(above.into())); + map.set(BlockNode::BELOW, VNode::strong(below.into())); - fn cast(value: Spanned<Value>) -> StrResult<Self> { - match value.v { - Value::Func(v) => Ok(Self::Func(v, value.span)), - v => T::cast(v) - .map(Self::Value) - .map_err(|msg| with_alternative(msg, "function")), - } + Ok(realized.styled_with_map(map)) } } diff --git a/library/src/structure/list.rs b/library/src/structure/list.rs index 89dc0f35..8de22f64 100644 --- a/library/src/structure/list.rs +++ b/library/src/structure/list.rs @@ -1,17 +1,15 @@ use unscanny::Scanner; use crate::base::Numbering; -use crate::layout::{BlockSpacing, GridNode, HNode, TrackSizing}; +use crate::layout::{BlockNode, GridNode, HNode, Spacing, TrackSizing}; use crate::prelude::*; use crate::text::{ParNode, SpaceNode, TextNode}; /// An unordered (bulleted) or ordered (numbered) list. -#[derive(Debug, Hash)] +#[derive(Debug, Clone, Hash)] pub struct ListNode<const L: ListKind = LIST> { /// If true, the items are separated by leading instead of list spacing. pub tight: bool, - /// If true, the spacing above the list is leading instead of above spacing. - pub attached: bool, /// The individual bulleted or numbered items. pub items: StyleVec<ListItem>, } @@ -22,7 +20,7 @@ pub type EnumNode = ListNode<ENUM>; /// A description list. pub type DescNode = ListNode<DESC>; -#[node(Show, Finalize)] +#[node(Show, LayoutBlock)] impl<const L: ListKind> ListNode<L> { /// How the list is labelled. #[property(referenced)] @@ -37,16 +35,8 @@ impl<const L: ListKind> ListNode<L> { DESC | _ => 1.0, }) .into(); - - /// The spacing above the list. - #[property(resolve, shorthand(around))] - pub const ABOVE: Option<BlockSpacing> = Some(Ratio::one().into()); - /// The spacing below the list. - #[property(resolve, shorthand(around))] - pub const BELOW: Option<BlockSpacing> = Some(Ratio::one().into()); /// The spacing between the items of a wide (non-tight) list. - #[property(resolve)] - pub const SPACING: BlockSpacing = Ratio::one().into(); + pub const SPACING: Smart<Spacing> = Smart::Auto; fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { let items = match L { @@ -73,18 +63,12 @@ impl<const L: ListKind> ListNode<L> { .collect(), }; - Ok(Self { - tight: args.named("tight")?.unwrap_or(true), - attached: args.named("attached")?.unwrap_or(false), - items, - } - .pack()) + Ok(Self { tight: args.named("tight")?.unwrap_or(true), items }.pack()) } fn field(&self, name: &str) -> Option<Value> { match name { "tight" => Some(Value::Bool(self.tight)), - "attached" => Some(Value::Bool(self.attached)), "items" => { Some(Value::Array(self.items.items().map(|item| item.encode()).collect())) } @@ -102,11 +86,18 @@ impl<const L: ListKind> Show for ListNode<L> { .pack() } - fn show( + fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> SourceResult<Content> { + Ok(self.clone().pack()) + } +} + +impl<const L: ListKind> LayoutBlock for ListNode<L> { + fn layout_block( &self, world: Tracked<dyn World>, + regions: &Regions, styles: StyleChain, - ) -> SourceResult<Content> { + ) -> SourceResult<Vec<Frame>> { let mut cells = vec![]; let mut number = 1; @@ -114,9 +105,11 @@ impl<const L: ListKind> Show for ListNode<L> { let indent = styles.get(Self::INDENT); let body_indent = styles.get(Self::BODY_INDENT); let gutter = if self.tight { - styles.get(ParNode::LEADING) + styles.get(ParNode::LEADING).into() } else { - styles.get(Self::SPACING) + styles + .get(Self::SPACING) + .unwrap_or_else(|| styles.get(BlockNode::BELOW).amount) }; for (item, map) in self.items.iter() { @@ -150,40 +143,17 @@ impl<const L: ListKind> Show for ListNode<L> { number += 1; } - Ok(GridNode { + GridNode { tracks: Axes::with_x(vec![ TrackSizing::Relative(indent.into()), TrackSizing::Auto, TrackSizing::Relative(body_indent.into()), TrackSizing::Auto, ]), - gutter: Axes::with_y(vec![TrackSizing::Relative(gutter.into())]), + gutter: Axes::with_y(vec![gutter.into()]), cells, } - .pack()) - } -} - -impl<const L: ListKind> Finalize for ListNode<L> { - fn finalize( - &self, - _: Tracked<dyn World>, - styles: StyleChain, - realized: Content, - ) -> SourceResult<Content> { - let mut above = styles.get(Self::ABOVE); - let mut below = styles.get(Self::BELOW); - - if self.attached { - if above.is_some() { - above = Some(styles.get(ParNode::LEADING)); - } - if below.is_some() { - below = Some(styles.get(ParNode::SPACING)); - } - } - - Ok(realized.spaced(above, below)) + .layout_block(world, regions, styles) } } diff --git a/library/src/structure/table.rs b/library/src/structure/table.rs index 8c6191be..72ea3da5 100644 --- a/library/src/structure/table.rs +++ b/library/src/structure/table.rs @@ -1,8 +1,8 @@ -use crate::layout::{BlockSpacing, GridNode, TrackSizing, TrackSizings}; +use crate::layout::{GridNode, TrackSizing, TrackSizings}; use crate::prelude::*; /// A table of items. -#[derive(Debug, Hash)] +#[derive(Debug, Clone, Hash)] pub struct TableNode { /// Defines sizing for content rows and columns. pub tracks: Axes<Vec<TrackSizing>>, @@ -12,7 +12,7 @@ pub struct TableNode { pub cells: Vec<Content>, } -#[node(Show, Finalize)] +#[node(Show, LayoutBlock)] impl TableNode { /// How to fill the cells. #[property(referenced)] @@ -23,13 +23,6 @@ impl TableNode { /// How much to pad the cells's content. pub const PADDING: Rel<Length> = Abs::pt(5.0).into(); - /// The spacing above the table. - #[property(resolve, shorthand(around))] - pub const ABOVE: Option<BlockSpacing> = Some(Ratio::one().into()); - /// The spacing below the table. - #[property(resolve, shorthand(around))] - pub const BELOW: Option<BlockSpacing> = Some(Ratio::one().into()); - fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { let TrackSizings(columns) = args.named("columns")?.unwrap_or_default(); let TrackSizings(rows) = args.named("rows")?.unwrap_or_default(); @@ -67,11 +60,18 @@ impl Show for TableNode { .pack() } - fn show( + fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> SourceResult<Content> { + Ok(self.clone().pack()) + } +} + +impl LayoutBlock for TableNode { + fn layout_block( &self, world: Tracked<dyn World>, + regions: &Regions, styles: StyleChain, - ) -> SourceResult<Content> { + ) -> SourceResult<Vec<Frame>> { let fill = styles.get(Self::FILL); let stroke = styles.get(Self::STROKE).map(PartialStroke::unwrap_or_default); let padding = styles.get(Self::PADDING); @@ -99,23 +99,12 @@ impl Show for TableNode { }) .collect::<SourceResult<_>>()?; - Ok(GridNode { + GridNode { tracks: self.tracks.clone(), gutter: self.gutter.clone(), cells, } - .pack()) - } -} - -impl Finalize for TableNode { - fn finalize( - &self, - _: Tracked<dyn World>, - styles: StyleChain, - realized: Content, - ) -> SourceResult<Content> { - Ok(realized.spaced(styles.get(Self::ABOVE), styles.get(Self::BELOW))) + .layout_block(world, regions, styles) } } |
