diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-04-30 14:12:28 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-04-30 14:12:28 +0200 |
| commit | f9e115daf54c29358f890b137f50a33a781af680 (patch) | |
| tree | 496de52246629ea8039db6beea94eb779ed2851d /src/library/structure | |
| parent | f7c67cde72e6a67f45180856b332bae9863243bd (diff) | |
New block spacing model
Diffstat (limited to 'src/library/structure')
| -rw-r--r-- | src/library/structure/heading.rs | 51 | ||||
| -rw-r--r-- | src/library/structure/list.rs | 48 | ||||
| -rw-r--r-- | src/library/structure/table.rs | 31 |
3 files changed, 76 insertions, 54 deletions
diff --git a/src/library/structure/heading.rs b/src/library/structure/heading.rs index a6c87912..4f6c54f3 100644 --- a/src/library/structure/heading.rs +++ b/src/library/structure/heading.rs @@ -1,3 +1,4 @@ +use crate::library::layout::BlockSpacing; use crate::library::prelude::*; use crate::library::text::{FontFamily, TextNode, TextSize, Toggle}; @@ -6,7 +7,7 @@ use crate::library::text::{FontFamily, TextNode, TextSize, Toggle}; pub struct HeadingNode { /// The logical nesting depth of the section, starting from one. In the /// default style, this controls the text size of the heading. - pub level: usize, + pub level: NonZeroUsize, /// The heading's contents. pub body: Content, } @@ -22,8 +23,12 @@ impl HeadingNode { /// The size of text in the heading. #[property(referenced)] pub const SIZE: Leveled<TextSize> = Leveled::Mapping(|level| { - let upscale = (1.6 - 0.1 * level as f64).max(0.75); - TextSize(Em::new(upscale).into()) + let size = match level.get() { + 1 => 1.4, + 2 => 1.2, + _ => 1.0, + }; + TextSize(Em::new(size).into()) }); /// Whether text in the heading is strengthend. @@ -36,21 +41,24 @@ impl HeadingNode { #[property(referenced)] pub const UNDERLINE: Leveled<bool> = Leveled::Value(false); - /// The extra padding above the heading. - #[property(referenced)] - pub const ABOVE: Leveled<RawLength> = Leveled::Value(Length::zero().into()); - /// The extra padding below the heading. - #[property(referenced)] - pub const BELOW: Leveled<RawLength> = Leveled::Value(Length::zero().into()); - - /// Whether the heading is block-level. - #[property(referenced)] - pub const BLOCK: Leveled<bool> = Leveled::Value(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 Context, args: &mut Args) -> TypResult<Content> { Ok(Content::show(Self { body: args.expect("body")?, - level: args.named("level")?.unwrap_or(1), + level: args.named("level")?.unwrap_or(NonZeroUsize::new(1).unwrap()), })) } } @@ -58,13 +66,13 @@ impl HeadingNode { impl Show for HeadingNode { fn encode(&self) -> Dict { dict! { - "level" => Value::Int(self.level as i64), + "level" => Value::Int(self.level.get() as i64), "body" => Value::Content(self.body.clone()), } } fn realize(&self, _: &mut Context, _: StyleChain) -> TypResult<Content> { - Ok(self.body.clone()) + Ok(Content::block(self.body.clone())) } fn finalize( @@ -103,11 +111,6 @@ impl Show for HeadingNode { } realized = realized.styled_with_map(map); - - if resolve!(Self::BLOCK) { - realized = Content::block(realized); - } - realized = realized.spaced( resolve!(Self::ABOVE).resolve(styles), resolve!(Self::BELOW).resolve(styles), @@ -123,19 +126,19 @@ pub enum Leveled<T> { /// A bare value. Value(T), /// A simple mapping from a heading level to a value. - Mapping(fn(usize) -> T), + 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, ctx: &mut Context, level: usize) -> TypResult<T> { + pub fn resolve(&self, ctx: &mut Context, level: NonZeroUsize) -> TypResult<T> { Ok(match self { Self::Value(value) => value.clone(), Self::Mapping(mapping) => mapping(level), Self::Func(func, span) => { - let args = Args::from_values(*span, [Value::Int(level as i64)]); + let args = Args::from_values(*span, [Value::Int(level.get() as i64)]); func.call(ctx, args)?.cast().at(*span)? } }) diff --git a/src/library/structure/list.rs b/src/library/structure/list.rs index ac705156..4356ffb4 100644 --- a/src/library/structure/list.rs +++ b/src/library/structure/list.rs @@ -2,7 +2,7 @@ use std::fmt::Write; use unscanny::Scanner; -use crate::library::layout::{GridNode, TrackSizing}; +use crate::library::layout::{BlockSpacing, GridNode, TrackSizing}; use crate::library::prelude::*; use crate::library::text::ParNode; use crate::library::utility::Numbering; @@ -12,9 +12,10 @@ use crate::library::utility::Numbering; pub struct ListNode<const L: ListKind = UNORDERED> { /// Where the list starts. pub start: usize, - /// If false, there is paragraph spacing between the items, if true - /// there is list spacing between the items. + /// 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>, } @@ -38,10 +39,6 @@ impl<const L: ListKind> ListNode<L> { /// How the list is labelled. #[property(referenced)] pub const LABEL: Label = Label::Default; - - /// The spacing between the list items of a non-wide list. - #[property(resolve)] - pub const SPACING: RawLength = RawLength::zero(); /// The indentation of each item's label. #[property(resolve)] pub const INDENT: RawLength = RawLength::zero(); @@ -49,17 +46,21 @@ impl<const L: ListKind> ListNode<L> { #[property(resolve)] pub const BODY_INDENT: RawLength = Em::new(0.5).into(); - /// The extra padding above the list. - #[property(resolve)] - pub const ABOVE: RawLength = RawLength::zero(); - /// The extra padding below the list. + /// 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 BELOW: RawLength = RawLength::zero(); + pub const SPACING: BlockSpacing = Ratio::one().into(); fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> { Ok(Content::show(Self { start: args.named("start")?.unwrap_or(1), tight: args.named("tight")?.unwrap_or(true), + attached: args.named("attached")?.unwrap_or(false), items: args .all()? .into_iter() @@ -78,6 +79,7 @@ impl<const L: ListKind> Show for ListNode<L> { dict! { "start" => Value::Int(self.start as i64), "tight" => Value::Bool(self.tight), + "attached" => Value::Bool(self.attached), "items" => Value::Array( self.items .items() @@ -103,14 +105,12 @@ impl<const L: ListKind> Show for ListNode<L> { number += 1; } - let leading = styles.get(ParNode::LEADING); - let spacing = if self.tight { - styles.get(Self::SPACING) + let gutter = if self.tight { + styles.get(ParNode::LEADING) } else { - styles.get(ParNode::SPACING) + styles.get(Self::SPACING) }; - let gutter = leading + spacing; let indent = styles.get(Self::INDENT); let body_indent = styles.get(Self::BODY_INDENT); @@ -132,7 +132,19 @@ impl<const L: ListKind> Show for ListNode<L> { styles: StyleChain, realized: Content, ) -> TypResult<Content> { - Ok(realized.spaced(styles.get(Self::ABOVE), styles.get(Self::BELOW))) + 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)) } } diff --git a/src/library/structure/table.rs b/src/library/structure/table.rs index 191d3dd3..7b3f2ac5 100644 --- a/src/library/structure/table.rs +++ b/src/library/structure/table.rs @@ -1,4 +1,4 @@ -use crate::library::layout::{GridNode, TrackSizing}; +use crate::library::layout::{BlockSpacing, GridNode, TrackSizing}; use crate::library::prelude::*; /// A table of items. @@ -15,16 +15,24 @@ pub struct TableNode { #[node(showable)] impl TableNode { /// The primary cell fill color. + #[property(shorthand(fill))] pub const PRIMARY: Option<Paint> = None; /// The secondary cell fill color. + #[property(shorthand(fill))] pub const SECONDARY: Option<Paint> = None; /// How to stroke the cells. #[property(resolve, fold)] pub const STROKE: Option<RawStroke> = Some(RawStroke::default()); - /// How much to pad the cells's content. pub const PADDING: Relative<RawLength> = Length::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 Context, args: &mut Args) -> TypResult<Content> { let columns = args.named("columns")?.unwrap_or_default(); let rows = args.named("rows")?.unwrap_or_default(); @@ -40,16 +48,6 @@ impl TableNode { cells: args.all()?, })) } - - fn set(args: &mut Args) -> TypResult<StyleMap> { - let mut styles = StyleMap::new(); - let fill = args.named("fill")?; - styles.set_opt(Self::PRIMARY, args.named("primary")?.or(fill)); - styles.set_opt(Self::SECONDARY, args.named("secondary")?.or(fill)); - styles.set_opt(Self::STROKE, args.named("stroke")?); - styles.set_opt(Self::PADDING, args.named("padding")?); - Ok(styles) - } } impl Show for TableNode { @@ -99,4 +97,13 @@ impl Show for TableNode { cells, })) } + + fn finalize( + &self, + _: &mut Context, + styles: StyleChain, + realized: Content, + ) -> TypResult<Content> { + Ok(realized.spaced(styles.get(Self::ABOVE), styles.get(Self::BELOW))) + } } |
