diff options
| author | Martin Haug <mhaug@live.de> | 2022-06-04 12:57:45 +0200 |
|---|---|---|
| committer | Martin Haug <mhaug@live.de> | 2022-06-04 12:57:45 +0200 |
| commit | 4640585fbdf72df993dbed46799844aa78996cce (patch) | |
| tree | 38a09389885a61068970441d6d27178a2ae4f115 /src/library | |
| parent | a937462491a63f5cff3551b5bb8bc45fb350f0b6 (diff) | |
First iteration of outline items
Diffstat (limited to 'src/library')
| -rw-r--r-- | src/library/graphics/hide.rs | 6 | ||||
| -rw-r--r-- | src/library/graphics/shape.rs | 3 | ||||
| -rw-r--r-- | src/library/layout/flow.rs | 7 | ||||
| -rw-r--r-- | src/library/layout/grid.rs | 44 | ||||
| -rw-r--r-- | src/library/layout/page.rs | 23 | ||||
| -rw-r--r-- | src/library/layout/stack.rs | 3 | ||||
| -rw-r--r-- | src/library/math/rex.rs | 1 | ||||
| -rw-r--r-- | src/library/structure/heading.rs | 12 | ||||
| -rw-r--r-- | src/library/structure/list.rs | 20 | ||||
| -rw-r--r-- | src/library/structure/table.rs | 16 | ||||
| -rw-r--r-- | src/library/text/par.rs | 5 | ||||
| -rw-r--r-- | src/library/text/raw.rs | 2 |
12 files changed, 123 insertions, 19 deletions
diff --git a/src/library/graphics/hide.rs b/src/library/graphics/hide.rs index 28afe320..4ba5e023 100644 --- a/src/library/graphics/hide.rs +++ b/src/library/graphics/hide.rs @@ -22,7 +22,11 @@ impl Layout for HideNode { // Clear the frames. for frame in &mut frames { - *frame = Arc::new(Frame { elements: vec![], ..**frame }); + *frame = Arc::new({ + let mut empty = Frame::new(frame.size); + empty.baseline = frame.baseline; + empty + }); } Ok(frames) diff --git a/src/library/graphics/shape.rs b/src/library/graphics/shape.rs index 9da8d8df..8070231e 100644 --- a/src/library/graphics/shape.rs +++ b/src/library/graphics/shape.rs @@ -91,6 +91,9 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> { let child = child.clone().padded(inset.map(|side| side.map(RawLength::from))); let mut pod = Regions::one(regions.first, regions.base, regions.expand); + let role_map = StyleMap::with_role(Role::GenericBlock); + let styles = role_map.chain(&styles); + frames = child.layout(ctx, &pod, styles)?; // Relayout with full expansion into square region to make sure diff --git a/src/library/layout/flow.rs b/src/library/layout/flow.rs index 6193a68f..0ba84b09 100644 --- a/src/library/layout/flow.rs +++ b/src/library/layout/flow.rs @@ -182,7 +182,12 @@ impl FlowLayouter { let frames = node.layout(ctx, &self.regions, styles)?; let len = frames.len(); - for (i, frame) in frames.into_iter().enumerate() { + for (i, mut frame) in frames.into_iter().enumerate() { + // Set the generic block role. + if frame.role().is_none() { + Arc::make_mut(&mut frame).apply_role(Role::GenericBlock); + } + // Grow our size, shrink the region and save the frame for later. let size = frame.size; self.used.y += size.y; diff --git a/src/library/layout/grid.rs b/src/library/layout/grid.rs index 4cad9de6..2517d193 100644 --- a/src/library/layout/grid.rs +++ b/src/library/layout/grid.rs @@ -9,6 +9,8 @@ pub struct GridNode { pub gutter: Spec<Vec<TrackSizing>>, /// The nodes to be arranged in a grid. pub cells: Vec<LayoutNode>, + /// The role of the grid in the semantic tree. + pub semantic: GridSemantics, } #[node] @@ -26,6 +28,7 @@ impl GridNode { row_gutter.unwrap_or(base_gutter), ), cells: args.all()?, + semantic: GridSemantics::None, })) } } @@ -45,6 +48,7 @@ impl Layout for GridNode { &self.cells, regions, styles, + self.semantic, ); // Measure the columns and layout the grid row-by-row. @@ -65,6 +69,28 @@ pub enum TrackSizing { Fractional(Fraction), } +/// Defines what kind of semantics a grid should represent. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum GridSemantics { + /// The grid is transparent to the semantic tree. + None, + /// The grid is a list, its rows are list items. The bool indicates whether + /// the list is ordered. + List, + /// The grid is a table. + Table, +} + +impl GridSemantics { + fn row(self) -> Option<Role> { + match self { + Self::None => None, + Self::List => Some(Role::ListItem), + Self::Table => Some(Role::TableRow), + } + } +} + castable! { Vec<TrackSizing>, Expected: "integer, auto, relative length, fraction, or array of the latter three)", @@ -104,6 +130,8 @@ pub struct GridLayouter<'a> { regions: Regions, /// The inherited styles. styles: StyleChain<'a>, + /// The role of the grid in the semantic tree. + semantic: GridSemantics, /// Resolved column sizes. rcols: Vec<Length>, /// Rows in the current region. @@ -139,6 +167,7 @@ impl<'a> GridLayouter<'a> { cells: &'a [LayoutNode], regions: &Regions, styles: StyleChain<'a>, + semantic: GridSemantics, ) -> Self { let mut cols = vec![]; let mut rows = vec![]; @@ -193,6 +222,7 @@ impl<'a> GridLayouter<'a> { rows, regions, styles, + semantic, rcols, lrows, full, @@ -450,6 +480,10 @@ impl<'a> GridLayouter<'a> { /// Layout a row with fixed height and return its frame. fn layout_single_row(&mut self, height: Length, y: usize) -> TypResult<Frame> { let mut output = Frame::new(Size::new(self.used.x, height)); + if let Some(role) = self.semantic.row() { + output.apply_role(role); + } + let mut pos = Point::zero(); for (x, &rcol) in self.rcols.iter().enumerate() { @@ -464,6 +498,7 @@ impl<'a> GridLayouter<'a> { let pod = Regions::one(size, base, Spec::splat(true)); let frame = node.layout(self.ctx, &pod, self.styles)?.remove(0); + output.push_frame(pos, frame); } @@ -482,7 +517,14 @@ impl<'a> GridLayouter<'a> { // Prepare frames. let mut outputs: Vec<_> = heights .iter() - .map(|&h| Frame::new(Size::new(self.used.x, h))) + .map(|&h| { + let mut f = Frame::new(Size::new(self.used.x, h)); + if let Some(role) = self.semantic.row() { + f.apply_role(role); + } + + f + }) .collect(); // Prepare regions. diff --git a/src/library/layout/page.rs b/src/library/layout/page.rs index 8435e510..d524839b 100644 --- a/src/library/layout/page.rs +++ b/src/library/layout/page.rs @@ -110,15 +110,28 @@ impl PageNode { let pad = padding.resolve(styles).relative_to(size); let pw = size.x - pad.left - pad.right; let py = size.y - pad.bottom; - for (marginal, pos, area) in [ - (header, Point::with_x(pad.left), Size::new(pw, pad.top)), - (footer, Point::new(pad.left, py), Size::new(pw, pad.bottom)), - (foreground, Point::zero(), size), - (background, Point::zero(), size), + for (marginal, pos, area, role) in [ + ( + header, + Point::with_x(pad.left), + Size::new(pw, pad.top), + Role::Header, + ), + ( + footer, + Point::new(pad.left, py), + Size::new(pw, pad.bottom), + Role::Footer, + ), + (foreground, Point::zero(), size, Role::Background), + (background, Point::zero(), size, Role::Background), ] { if let Some(content) = marginal.resolve(ctx, page)? { let pod = Regions::one(area, area, Spec::splat(true)); + let role_map = StyleMap::with_role(role); + let styles = role_map.chain(&styles); let sub = content.layout(ctx, &pod, styles)?.remove(0); + if std::ptr::eq(marginal, background) { Arc::make_mut(frame).prepend_frame(pos, sub); } else { diff --git a/src/library/layout/stack.rs b/src/library/layout/stack.rs index 828ff8e3..7bad01d9 100644 --- a/src/library/layout/stack.rs +++ b/src/library/layout/stack.rs @@ -192,6 +192,9 @@ impl<'a> StackLayouter<'a> { self.dir.start().into() }); + let role_map = StyleMap::with_role(Role::GenericBlock); + let styles = role_map.chain(&styles); + let frames = node.layout(ctx, &self.regions, styles)?; let len = frames.len(); for (i, frame) in frames.into_iter().enumerate() { diff --git a/src/library/math/rex.rs b/src/library/math/rex.rs index 0268fb9c..f839a9e8 100644 --- a/src/library/math/rex.rs +++ b/src/library/math/rex.rs @@ -66,6 +66,7 @@ impl Layout for RexNode { let mut backend = FrameBackend { frame: { let mut frame = Frame::new(size); + frame.apply_role(Role::Formula); frame.baseline = Some(baseline); frame }, diff --git a/src/library/structure/heading.rs b/src/library/structure/heading.rs index a0973b90..285793dd 100644 --- a/src/library/structure/heading.rs +++ b/src/library/structure/heading.rs @@ -1,6 +1,7 @@ use crate::library::layout::BlockSpacing; use crate::library::prelude::*; use crate::library::text::{FontFamily, TextNode, TextSize}; +use crate::model::StyleEntry; /// A section heading. #[derive(Debug, Hash)] @@ -65,7 +66,13 @@ impl HeadingNode { impl Show for HeadingNode { fn unguard(&self, sel: Selector) -> ShowNode { - Self { body: self.body.unguard(sel), ..*self }.pack() + let mut map = StyleMap::with_role(Role::Heading(self.level.get())); + map.push(StyleEntry::Unguard(sel)); + Self { + body: self.body.clone().styled_with_map(map), + ..*self + } + .pack() } fn encode(&self, _: StyleChain) -> Dict { @@ -91,7 +98,8 @@ impl Show for HeadingNode { }; } - let mut map = StyleMap::new(); + let mut map = StyleMap::with_role(Role::Heading(self.level.get())); + map.set(TextNode::SIZE, resolve!(Self::SIZE)); if let Smart::Custom(family) = resolve!(Self::FAMILY) { diff --git a/src/library/structure/list.rs b/src/library/structure/list.rs index 84603eb3..563426b4 100644 --- a/src/library/structure/list.rs +++ b/src/library/structure/list.rs @@ -2,10 +2,11 @@ use std::fmt::Write; use unscanny::Scanner; -use crate::library::layout::{BlockSpacing, GridNode, TrackSizing}; +use crate::library::layout::{BlockSpacing, GridNode, GridSemantics, TrackSizing}; use crate::library::prelude::*; use crate::library::text::ParNode; use crate::library::utility::Numbering; +use crate::model::StyleEntry; /// An unordered (bulleted) or ordered (numbered) list. #[derive(Debug, Hash)] @@ -76,9 +77,12 @@ impl<const L: ListKind> ListNode<L> { impl<const L: ListKind> Show for ListNode<L> { fn unguard(&self, sel: Selector) -> ShowNode { + let mut map = StyleMap::with_role(Role::ListItemBody); + map.push(StyleEntry::Unguard(sel)); + Self { items: self.items.map(|item| ListItem { - body: Box::new(item.body.unguard(sel)), + body: Box::new(item.body.clone().styled_with_map(map.clone())), ..*item }), ..*self @@ -108,9 +112,12 @@ impl<const L: ListKind> Show for ListNode<L> { for (item, map) in self.items.iter() { number = item.number.unwrap_or(number); + + let mut label_map = map.clone(); + label_map.push(StyleEntry::Role(Role::ListLabel)); + cells.push(LayoutNode::default()); - cells - .push(label.resolve(ctx, L, number)?.styled_with_map(map.clone()).pack()); + cells.push(label.resolve(ctx, L, number)?.styled_with_map(label_map).pack()); cells.push(LayoutNode::default()); cells.push((*item.body).clone().styled_with_map(map.clone()).pack()); number += 1; @@ -134,6 +141,7 @@ impl<const L: ListKind> Show for ListNode<L> { ]), gutter: Spec::with_y(vec![TrackSizing::Relative(gutter.into())]), cells, + semantic: GridSemantics::List, })) } @@ -155,7 +163,9 @@ impl<const L: ListKind> Show for ListNode<L> { } } - Ok(realized.spaced(above, below)) + Ok(realized + .styled_with_map(StyleMap::with_role(Role::List(L == ORDERED))) + .spaced(above, below)) } } diff --git a/src/library/structure/table.rs b/src/library/structure/table.rs index cd70db30..60115612 100644 --- a/src/library/structure/table.rs +++ b/src/library/structure/table.rs @@ -1,5 +1,6 @@ -use crate::library::layout::{BlockSpacing, GridNode, TrackSizing}; +use crate::library::layout::{BlockSpacing, GridNode, GridSemantics, TrackSizing}; use crate::library::prelude::*; +use crate::model::StyleEntry; /// A table of items. #[derive(Debug, Hash)] @@ -49,10 +50,17 @@ impl TableNode { impl Show for TableNode { fn unguard(&self, sel: Selector) -> ShowNode { + let mut map = StyleMap::with_role(Role::TableCell); + map.push(StyleEntry::Unguard(sel)); + Self { tracks: self.tracks.clone(), gutter: self.gutter.clone(), - cells: self.cells.iter().map(|cell| cell.unguard(sel)).collect(), + cells: self + .cells + .iter() + .map(|cell| cell.clone().styled_with_map(map.clone())) + .collect(), } .pack() } @@ -100,7 +108,9 @@ impl Show for TableNode { tracks: self.tracks.clone(), gutter: self.gutter.clone(), cells, - })) + semantic: GridSemantics::Table, + }) + .styled_with_map(StyleMap::with_role(Role::Table))) } fn finalize( diff --git a/src/library/text/par.rs b/src/library/text/par.rs index 695d8066..53bb798f 100644 --- a/src/library/text/par.rs +++ b/src/library/text/par.rs @@ -551,6 +551,9 @@ fn prepare<'a>( } else { let size = Size::new(regions.first.x, regions.base.y); let pod = Regions::one(size, regions.base, Spec::splat(false)); + let role_map = StyleMap::with_role(Role::GenericInline); + let styles = role_map.chain(&styles); + let mut frame = node.layout(ctx, &pod, styles)?.remove(0); let shift = styles.get(TextNode::BASELINE); @@ -1063,6 +1066,7 @@ fn stack( let mut finished = vec![]; let mut first = true; let mut output = Frame::new(Size::with_x(width)); + output.apply_role(Role::Paragraph); // Stack the lines into one frame per region. for line in lines { @@ -1072,6 +1076,7 @@ fn stack( while !regions.first.y.fits(height) && !regions.in_last() { finished.push(Arc::new(output)); output = Frame::new(Size::with_x(width)); + output.apply_role(Role::Paragraph); regions.next(); first = true; } diff --git a/src/library/text/raw.rs b/src/library/text/raw.rs index a24d2170..4d73b11b 100644 --- a/src/library/text/raw.rs +++ b/src/library/text/raw.rs @@ -113,7 +113,7 @@ impl Show for RawNode { styles: StyleChain, mut realized: Content, ) -> TypResult<Content> { - let mut map = StyleMap::new(); + let mut map = StyleMap::with_role(Role::Code); map.set_family(styles.get(Self::FAMILY).clone(), styles); map.set(TextNode::OVERHANG, false); map.set(TextNode::HYPHENATE, Smart::Custom(Hyphenate(false))); |
