summaryrefslogtreecommitdiff
path: root/library/src/structure
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-11-09 18:16:59 +0100
committerLaurenz <laurmaedje@gmail.com>2022-11-09 18:20:02 +0100
commit010cc2effc2fd0e1c4e52d5c914cb4d74506bc0a (patch)
treee50060d271f076b00945e5569e7f8ffef2c28e9f /library/src/structure
parent12a59963b08b68cc39dcded4d3d3e6a6631c2732 (diff)
New block spacing model
Diffstat (limited to 'library/src/structure')
-rw-r--r--library/src/structure/heading.rs102
-rw-r--r--library/src/structure/list.rs72
-rw-r--r--library/src/structure/table.rs39
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)
}
}