Auto-detect grid row semantics

This commit is contained in:
Martin Haug 2022-06-08 13:11:51 +02:00
parent 6d8b65c4b2
commit 995a7882d2
4 changed files with 31 additions and 27 deletions

View File

@ -9,8 +9,6 @@ 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]
@ -28,7 +26,6 @@ impl GridNode {
row_gutter.unwrap_or(base_gutter),
),
cells: args.all()?,
semantic: GridSemantics::None,
}))
}
}
@ -48,7 +45,6 @@ impl Layout for GridNode {
&self.cells,
regions,
styles,
self.semantic,
);
// Measure the columns and layout the grid row-by-row.
@ -71,7 +67,7 @@ pub enum TrackSizing {
/// Defines what kind of semantics a grid should represent.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum GridSemantics {
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
@ -82,6 +78,7 @@ pub enum GridSemantics {
}
impl GridSemantics {
/// The role of a row in a grid with these semantics.
fn row(self) -> Option<Role> {
match self {
Self::None => None,
@ -89,6 +86,18 @@ impl GridSemantics {
Self::Table => Some(Role::TableRow),
}
}
/// Returns the semantic role of a grid row given the previous semantics and
/// the cell's role.
fn determine(other: Option<Self>, role: Option<Role>) -> Self {
match (other, role) {
(None, Some(Role::ListItem | Role::ListLabel)) => Self::List,
(Some(Self::List), Some(Role::ListItem | Role::ListLabel)) => Self::List,
(None, Some(Role::TableCell)) => Self::Table,
(Some(Self::Table), Some(Role::TableCell)) => Self::Table,
_ => Self::None,
}
}
}
castable! {
@ -130,8 +139,6 @@ 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.
@ -167,7 +174,6 @@ impl<'a> GridLayouter<'a> {
cells: &'a [LayoutNode],
regions: &Regions,
styles: StyleChain<'a>,
semantic: GridSemantics,
) -> Self {
let mut cols = vec![];
let mut rows = vec![];
@ -222,7 +228,6 @@ impl<'a> GridLayouter<'a> {
rows,
regions,
styles,
semantic,
rcols,
lrows,
full,
@ -480,11 +485,9 @@ 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();
let mut semantic = None;
for (x, &rcol) in self.rcols.iter().enumerate() {
if let Some(node) = self.cell(x, y) {
@ -498,6 +501,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);
semantic = Some(GridSemantics::determine(semantic, frame.role()));
output.push_frame(pos, frame);
}
@ -505,6 +509,10 @@ impl<'a> GridLayouter<'a> {
pos.x += rcol;
}
if let Some(role) = semantic.and_then(GridSemantics::row) {
output.apply_role(role);
}
Ok(output)
}
@ -517,14 +525,7 @@ impl<'a> GridLayouter<'a> {
// Prepare frames.
let mut outputs: Vec<_> = heights
.iter()
.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
})
.map(|&h| Frame::new(Size::new(self.used.x, h)))
.collect();
// Prepare regions.
@ -534,6 +535,7 @@ impl<'a> GridLayouter<'a> {
// Layout the row.
let mut pos = Point::zero();
let mut semantic = None;
for (x, &rcol) in self.rcols.iter().enumerate() {
if let Some(node) = self.cell(x, y) {
pod.first.x = rcol;
@ -547,6 +549,7 @@ impl<'a> GridLayouter<'a> {
// Push the layouted frames into the individual output frames.
let frames = node.layout(self.ctx, &pod, self.styles)?;
for (output, frame) in outputs.iter_mut().zip(frames) {
semantic = Some(GridSemantics::determine(semantic, frame.role()));
output.push_frame(pos, frame);
}
}
@ -554,6 +557,12 @@ impl<'a> GridLayouter<'a> {
pos.x += rcol;
}
for output in outputs.iter_mut() {
if let Some(role) = semantic.and_then(GridSemantics::row) {
output.apply_role(role);
}
}
Ok(outputs)
}

View File

@ -1,7 +1,6 @@
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)]

View File

@ -2,11 +2,10 @@ use std::fmt::Write;
use unscanny::Scanner;
use crate::library::layout::{BlockSpacing, GridNode, GridSemantics, TrackSizing};
use crate::library::layout::{BlockSpacing, GridNode, 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)]
@ -141,7 +140,6 @@ impl<const L: ListKind> Show for ListNode<L> {
]),
gutter: Spec::with_y(vec![TrackSizing::Relative(gutter.into())]),
cells,
semantic: GridSemantics::List,
}))
}

View File

@ -1,6 +1,5 @@
use crate::library::layout::{BlockSpacing, GridNode, GridSemantics, TrackSizing};
use crate::library::layout::{BlockSpacing, GridNode, TrackSizing};
use crate::library::prelude::*;
use crate::model::StyleEntry;
/// A table of items.
#[derive(Debug, Hash)]
@ -105,7 +104,6 @@ impl Show for TableNode {
tracks: self.tracks.clone(),
gutter: self.gutter.clone(),
cells,
semantic: GridSemantics::Table,
})
.role(Role::Table))
}