Some table improvements [More flexible tables] (#3473)
This commit is contained in:
parent
92a2f01b74
commit
a8671962d6
@ -332,7 +332,7 @@ impl CellGrid {
|
||||
items: I,
|
||||
fill: &Celled<Option<Paint>>,
|
||||
align: &Celled<Smart<Alignment>>,
|
||||
inset: Sides<Option<Rel<Length>>>,
|
||||
inset: &Celled<Sides<Option<Rel<Length>>>>,
|
||||
stroke: &ResolvedCelled<Sides<Option<Option<Arc<Stroke>>>>>,
|
||||
engine: &mut Engine,
|
||||
styles: StyleChain,
|
||||
@ -486,7 +486,7 @@ impl CellGrid {
|
||||
y,
|
||||
&fill.resolve(engine, x, y)?,
|
||||
align.resolve(engine, x, y)?,
|
||||
inset,
|
||||
inset.resolve(engine, x, y)?,
|
||||
stroke.resolve(engine, styles, x, y)?,
|
||||
styles,
|
||||
);
|
||||
@ -572,7 +572,7 @@ impl CellGrid {
|
||||
y,
|
||||
&fill.resolve(engine, x, y)?,
|
||||
align.resolve(engine, x, y)?,
|
||||
inset,
|
||||
inset.resolve(engine, x, y)?,
|
||||
stroke.resolve(engine, styles, x, y)?,
|
||||
styles,
|
||||
);
|
||||
|
@ -130,7 +130,7 @@ where
|
||||
&CellGrid,
|
||||
usize,
|
||||
usize,
|
||||
Option<Arc<Stroke<Abs>>>,
|
||||
Option<Option<Arc<Stroke<Abs>>>>,
|
||||
) -> Option<(Arc<Stroke<Abs>>, StrokePriority)>
|
||||
+ 'grid,
|
||||
I: IntoIterator<Item = (usize, Abs)>,
|
||||
@ -204,7 +204,7 @@ where
|
||||
// Get the expected line stroke at this track by folding the
|
||||
// strokes of each user-specified line (with priority to the
|
||||
// user-specified line specified last).
|
||||
let stroke = lines
|
||||
let mut line_strokes = lines
|
||||
.iter()
|
||||
.filter(|line| {
|
||||
line.position == expected_line_position
|
||||
@ -222,8 +222,15 @@ where
|
||||
})
|
||||
.unwrap_or_else(|| track >= gutter_factor * line.start)
|
||||
})
|
||||
.map(|line| line.stroke.clone())
|
||||
.fold(None, |acc, line_stroke| line_stroke.fold(acc));
|
||||
.map(|line| line.stroke.clone());
|
||||
|
||||
// Distinguish between unspecified stroke (None, if no lines
|
||||
// were matched above) and specified stroke of None (Some(None),
|
||||
// if some lines were matched and the one specified last had a
|
||||
// stroke of None) by conditionally folding after 'next()'.
|
||||
let line_stroke = line_strokes.next().map(|first_stroke| {
|
||||
line_strokes.fold(first_stroke, |acc, line_stroke| line_stroke.fold(acc))
|
||||
});
|
||||
|
||||
// The function shall determine if it is appropriate to draw
|
||||
// the line at this position or not (i.e. whether or not it
|
||||
@ -240,7 +247,7 @@ where
|
||||
// (which indicates, in the context of 'std::iter::from_fn', that
|
||||
// our iterator isn't over yet, and this should be its next value).
|
||||
if let Some((stroke, priority)) =
|
||||
line_stroke_at_track(grid, index, track, stroke)
|
||||
line_stroke_at_track(grid, index, track, line_stroke)
|
||||
{
|
||||
// We should draw at this position. Let's check if we were
|
||||
// already drawing in the previous position.
|
||||
@ -301,9 +308,10 @@ where
|
||||
}
|
||||
|
||||
/// Returns the correct stroke with which to draw a vline right before column
|
||||
/// 'x' when going through row 'y', given the stroke of the user-specified line
|
||||
/// at this position, if any. Also returns the stroke's drawing priority, which
|
||||
/// depends on its source.
|
||||
/// `x` when going through row `y`, given the stroke of the user-specified line
|
||||
/// at this position, if any (note that a stroke of `None` is unspecified,
|
||||
/// while `Some(None)` means specified to remove any stroke at this position).
|
||||
/// Also returns the stroke's drawing priority, which depends on its source.
|
||||
///
|
||||
/// If the vline would go through a colspan, returns None (shouldn't be drawn).
|
||||
/// If the one (when at the border) or two (otherwise) cells to the left and
|
||||
@ -317,12 +325,12 @@ where
|
||||
/// stroke, as defined by user-specified lines (if any), is returned.
|
||||
///
|
||||
/// The priority associated with the returned stroke follows the rules
|
||||
/// described in the docs for 'generate_line_segment'.
|
||||
/// described in the docs for `generate_line_segment`.
|
||||
pub(super) fn vline_stroke_at_row(
|
||||
grid: &CellGrid,
|
||||
x: usize,
|
||||
y: usize,
|
||||
stroke: Option<Arc<Stroke<Abs>>>,
|
||||
stroke: Option<Option<Arc<Stroke<Abs>>>>,
|
||||
) -> Option<(Arc<Stroke<Abs>>, StrokePriority)> {
|
||||
if x != 0 && x != grid.cols.len() {
|
||||
// When the vline isn't at the border, we need to check if a colspan would
|
||||
@ -397,15 +405,16 @@ pub(super) fn vline_stroke_at_row(
|
||||
// Fold the line stroke and folded cell strokes, if possible.
|
||||
// Give priority to the explicit line stroke.
|
||||
// Otherwise, use whichever of the two isn't 'none' or unspecified.
|
||||
let final_stroke = stroke.fold_or(cell_stroke);
|
||||
let final_stroke = stroke.fold_or(Some(cell_stroke)).flatten();
|
||||
|
||||
final_stroke.zip(Some(priority))
|
||||
}
|
||||
|
||||
/// Returns the correct stroke with which to draw a hline on top of row 'y'
|
||||
/// when going through column 'x', given the stroke of the user-specified line
|
||||
/// at this position, if any. Also returns the stroke's drawing priority, which
|
||||
/// depends on its source.
|
||||
/// Returns the correct stroke with which to draw a hline on top of row `y`
|
||||
/// when going through column `x`, given the stroke of the user-specified line
|
||||
/// at this position, if any (note that a stroke of `None` is unspecified,
|
||||
/// while `Some(None)` means specified to remove any stroke at this position).
|
||||
/// Also returns the stroke's drawing priority, which depends on its source.
|
||||
///
|
||||
/// If the one (when at the border) or two (otherwise) cells above and below
|
||||
/// the hline have bottom and top stroke overrides, respectively, then the
|
||||
@ -418,12 +427,12 @@ pub(super) fn vline_stroke_at_row(
|
||||
/// defined by user-specified lines (if any), is directly returned.
|
||||
///
|
||||
/// The priority associated with the returned stroke follows the rules
|
||||
/// described in the docs for 'generate_line_segment'.
|
||||
/// described in the docs for `generate_line_segment`.
|
||||
pub(super) fn hline_stroke_at_column(
|
||||
grid: &CellGrid,
|
||||
y: usize,
|
||||
x: usize,
|
||||
stroke: Option<Arc<Stroke<Abs>>>,
|
||||
stroke: Option<Option<Arc<Stroke<Abs>>>>,
|
||||
) -> Option<(Arc<Stroke<Abs>>, StrokePriority)> {
|
||||
// There are no rowspans yet, so no need to add a check here. The line will
|
||||
// always be drawn, if it has a stroke.
|
||||
@ -505,7 +514,7 @@ pub(super) fn hline_stroke_at_column(
|
||||
// Fold the line stroke and folded cell strokes, if possible.
|
||||
// Give priority to the explicit line stroke.
|
||||
// Otherwise, use whichever of the two isn't 'none' or unspecified.
|
||||
let final_stroke = stroke.fold_or(cell_stroke);
|
||||
let final_stroke = stroke.fold_or(Some(cell_stroke)).flatten();
|
||||
|
||||
final_stroke.zip(Some(priority))
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use std::sync::Arc;
|
||||
use ecow::eco_format;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use crate::diag::{SourceResult, StrResult, Trace, Tracepoint};
|
||||
use crate::diag::{bail, SourceResult, StrResult, Trace, Tracepoint};
|
||||
use crate::engine::Engine;
|
||||
use crate::foundations::{
|
||||
cast, elem, scope, Array, Content, Fold, Packed, Show, Smart, StyleChain, Value,
|
||||
@ -19,6 +19,7 @@ use crate::layout::{
|
||||
Abs, AlignElem, Alignment, Axes, Dir, Fragment, LayoutMultiple, Length,
|
||||
OuterHAlignment, OuterVAlignment, Regions, Rel, Sides, Sizing,
|
||||
};
|
||||
use crate::model::{TableCell, TableHLine, TableVLine};
|
||||
use crate::syntax::Span;
|
||||
use crate::text::TextElem;
|
||||
use crate::util::NonZeroExt;
|
||||
@ -270,7 +271,7 @@ pub struct GridElem {
|
||||
/// )
|
||||
/// ```
|
||||
#[fold]
|
||||
pub inset: Sides<Option<Rel<Length>>>,
|
||||
pub inset: Celled<Sides<Option<Rel<Length>>>>,
|
||||
|
||||
/// The contents of the grid cells, plus any extra grid lines specified
|
||||
/// with the [`grid.hline`]($grid.hline) and [`grid.vline`]($grid.vline)
|
||||
@ -353,7 +354,7 @@ impl LayoutMultiple for Packed<GridElem> {
|
||||
items,
|
||||
fill,
|
||||
align,
|
||||
inset,
|
||||
&inset,
|
||||
&stroke,
|
||||
engine,
|
||||
styles,
|
||||
@ -395,7 +396,24 @@ cast! {
|
||||
Self::VLine(vline) => vline.into_value(),
|
||||
Self::Cell(cell) => cell.into_value(),
|
||||
},
|
||||
v: Content => v.into(),
|
||||
v: Content => {
|
||||
if v.is::<TableCell>() {
|
||||
bail!(
|
||||
"cannot use `table.cell` as a grid cell; use `grid.cell` instead"
|
||||
);
|
||||
}
|
||||
if v.is::<TableHLine>() {
|
||||
bail!(
|
||||
"cannot use `table.hline` as a grid line; use `grid.hline` instead"
|
||||
);
|
||||
}
|
||||
if v.is::<TableVLine>() {
|
||||
bail!(
|
||||
"cannot use `table.vline` as a grid line; use `grid.vline` instead"
|
||||
);
|
||||
}
|
||||
v.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Content> for GridChild {
|
||||
|
@ -3,15 +3,16 @@ use std::sync::Arc;
|
||||
|
||||
use ecow::eco_format;
|
||||
|
||||
use crate::diag::{SourceResult, Trace, Tracepoint};
|
||||
use crate::diag::{bail, SourceResult, Trace, Tracepoint};
|
||||
use crate::engine::Engine;
|
||||
use crate::foundations::{
|
||||
cast, elem, scope, Content, Fold, Packed, Show, Smart, StyleChain,
|
||||
};
|
||||
use crate::layout::{
|
||||
show_grid_cell, Abs, Alignment, Axes, Cell, CellGrid, Celled, Dir, Fragment,
|
||||
GridItem, GridLayouter, LayoutMultiple, Length, LinePosition, OuterHAlignment,
|
||||
OuterVAlignment, Regions, Rel, ResolvableCell, Sides, TrackSizings,
|
||||
GridCell, GridHLine, GridItem, GridLayouter, GridVLine, LayoutMultiple, Length,
|
||||
LinePosition, OuterHAlignment, OuterVAlignment, Regions, Rel, ResolvableCell, Sides,
|
||||
TrackSizings,
|
||||
};
|
||||
use crate::model::Figurable;
|
||||
use crate::syntax::Span;
|
||||
@ -200,8 +201,8 @@ pub struct TableElem {
|
||||
/// )
|
||||
/// ```
|
||||
#[fold]
|
||||
#[default(Sides::splat(Some(Abs::pt(5.0).into())))]
|
||||
pub inset: Sides<Option<Rel<Length>>>,
|
||||
#[default(Celled::Value(Sides::splat(Some(Abs::pt(5.0).into()))))]
|
||||
pub inset: Celled<Sides<Option<Rel<Length>>>>,
|
||||
|
||||
/// The contents of the table cells, plus any extra table lines specified
|
||||
/// with the [`table.hline`]($table.hline) and
|
||||
@ -282,7 +283,7 @@ impl LayoutMultiple for Packed<TableElem> {
|
||||
items,
|
||||
fill,
|
||||
align,
|
||||
inset,
|
||||
&inset,
|
||||
&stroke,
|
||||
engine,
|
||||
styles,
|
||||
@ -349,7 +350,24 @@ cast! {
|
||||
Self::VLine(vline) => vline.into_value(),
|
||||
Self::Cell(cell) => cell.into_value(),
|
||||
},
|
||||
v: Content => v.into(),
|
||||
v: Content => {
|
||||
if v.is::<GridCell>() {
|
||||
bail!(
|
||||
"cannot use `grid.cell` as a table cell; use `table.cell` instead"
|
||||
);
|
||||
}
|
||||
if v.is::<GridHLine>() {
|
||||
bail!(
|
||||
"cannot use `grid.hline` as a table line; use `table.hline` instead"
|
||||
);
|
||||
}
|
||||
if v.is::<GridVLine>() {
|
||||
bail!(
|
||||
"cannot use `grid.vline` as a table line; use `table.vline` instead"
|
||||
);
|
||||
}
|
||||
v.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Content> for TableChild {
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Binary file not shown.
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 30 KiB |
Binary file not shown.
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 26 KiB |
@ -127,3 +127,7 @@
|
||||
[Jake], [49], [Epic]
|
||||
)
|
||||
}
|
||||
|
||||
---
|
||||
// Error: 7-19 cannot use `table.cell` as a grid cell; use `grid.cell` instead
|
||||
#grid(table.cell[])
|
||||
|
@ -139,7 +139,7 @@
|
||||
---
|
||||
// Line specification order priority
|
||||
// The last line should be blue, not red.
|
||||
// The middle line should have disappeared.
|
||||
// The middle aqua line should be gone due to the 'none' override.
|
||||
#grid(
|
||||
columns: 2,
|
||||
inset: 2pt,
|
||||
@ -344,6 +344,22 @@
|
||||
table.vline(x: 3)
|
||||
)
|
||||
|
||||
---
|
||||
// Error: 7-20 cannot use `table.hline` as a grid line; use `grid.hline` instead
|
||||
#grid(table.hline())
|
||||
|
||||
---
|
||||
// Error: 7-20 cannot use `table.vline` as a grid line; use `grid.vline` instead
|
||||
#grid(table.vline())
|
||||
|
||||
---
|
||||
// Error: 8-20 cannot use `grid.hline` as a table line; use `table.hline` instead
|
||||
#table(grid.hline())
|
||||
|
||||
---
|
||||
// Error: 8-20 cannot use `grid.vline` as a table line; use `table.vline` instead
|
||||
#table(grid.vline())
|
||||
|
||||
---
|
||||
// Error: 3:3-3:31 line cannot end before it starts
|
||||
#grid(
|
||||
|
@ -88,6 +88,32 @@ a
|
||||
[B],
|
||||
)
|
||||
|
||||
#grid(
|
||||
columns: 3,
|
||||
fill: (x, y) => (if y == 0 { aqua } else { orange }).darken(x * 15%),
|
||||
inset: (x, y) => (left: if x == 0 { 0pt } else { 5pt }, right: if x == 0 { 5pt } else { 0pt }, y: if y == 0 { 0pt } else { 5pt }),
|
||||
[A], [B], [C],
|
||||
[A], [B], [C],
|
||||
)
|
||||
|
||||
#grid(
|
||||
columns: 3,
|
||||
inset: (0pt, 5pt, 10pt),
|
||||
fill: (x, _) => aqua.darken(x * 15%),
|
||||
[A], [B], [C],
|
||||
)
|
||||
|
||||
---
|
||||
// Test inset folding
|
||||
#set grid(inset: 10pt)
|
||||
#set grid(inset: (left: 0pt))
|
||||
|
||||
#grid(
|
||||
fill: red,
|
||||
inset: (right: 0pt),
|
||||
grid.cell(inset: (top: 0pt))[a]
|
||||
)
|
||||
|
||||
---
|
||||
// Test interaction with gutters.
|
||||
#grid(
|
||||
|
@ -122,3 +122,7 @@
|
||||
[Jake], [49], [Epic]
|
||||
)
|
||||
}
|
||||
|
||||
---
|
||||
// Error: 8-19 cannot use `grid.cell` as a table cell; use `table.cell` instead
|
||||
#table(grid.cell[])
|
||||
|
@ -61,6 +61,32 @@
|
||||
[B],
|
||||
)
|
||||
|
||||
#table(
|
||||
columns: 3,
|
||||
fill: (x, y) => (if y == 0 { aqua } else { orange }).darken(x * 15%),
|
||||
inset: (x, y) => (left: if x == 0 { 0pt } else { 5pt }, right: if x == 0 { 5pt } else { 0pt }, y: if y == 0 { 0pt } else { 5pt }),
|
||||
[A], [B], [C],
|
||||
[A], [B], [C],
|
||||
)
|
||||
|
||||
#table(
|
||||
columns: 3,
|
||||
inset: (0pt, 5pt, 10pt),
|
||||
fill: (x, _) => aqua.darken(x * 15%),
|
||||
[A], [B], [C],
|
||||
)
|
||||
|
||||
---
|
||||
// Test inset folding
|
||||
#set table(inset: 10pt)
|
||||
#set table(inset: (left: 0pt))
|
||||
|
||||
#table(
|
||||
fill: red,
|
||||
inset: (right: 0pt),
|
||||
table.cell(inset: (top: 0pt))[a]
|
||||
)
|
||||
|
||||
---
|
||||
// Test interaction with gutters.
|
||||
#table(
|
||||
|
Loading…
Reference in New Issue
Block a user