mirror of
https://github.com/typst/typst
synced 2025-07-27 14:27:56 +08:00
refactor: remove general api to set cell kind and add pdf.(header|data)-cell
This commit is contained in:
parent
070a0faf5c
commit
edd213074f
@ -22,7 +22,7 @@ use typst_syntax::Span;
|
||||
use typst_utils::NonZeroExt;
|
||||
|
||||
use crate::introspection::SplitLocator;
|
||||
use crate::model::{TableCellKind, TableHeaderScope};
|
||||
use crate::pdf::{TableCellKind, TableHeaderScope};
|
||||
|
||||
/// Convert a grid to a cell grid.
|
||||
#[typst_macros::time(span = elem.span())]
|
||||
@ -226,7 +226,7 @@ impl ResolvableCell for Packed<TableCell> {
|
||||
let breakable = cell.breakable(styles).unwrap_or(breakable);
|
||||
let fill = cell.fill(styles).unwrap_or_else(|| fill.clone());
|
||||
|
||||
let kind = cell.kind(styles).or(kind);
|
||||
let kind = cell.kind().copied().unwrap_or_default().or(kind);
|
||||
|
||||
let cell_stroke = cell.stroke(styles);
|
||||
let stroke_overridden =
|
||||
|
@ -2,14 +2,13 @@ use std::num::{NonZeroU32, NonZeroUsize};
|
||||
use std::sync::Arc;
|
||||
|
||||
use ecow::EcoString;
|
||||
use typst_macros::Cast;
|
||||
use typst_utils::NonZeroExt;
|
||||
|
||||
use crate::diag::{bail, HintedStrResult, HintedString, SourceResult};
|
||||
use crate::engine::Engine;
|
||||
use crate::foundations::{
|
||||
cast, dict, elem, scope, Content, Dict, NativeElement, Packed, Show, Smart,
|
||||
StyleChain, TargetElem,
|
||||
cast, elem, scope, Content, NativeElement, Packed, Show, Smart, StyleChain,
|
||||
TargetElem,
|
||||
};
|
||||
use crate::html::{attr, tag, HtmlAttrs, HtmlElem, HtmlTag};
|
||||
use crate::introspection::{Locatable, Locator};
|
||||
@ -20,6 +19,7 @@ use crate::layout::{
|
||||
TrackSizings,
|
||||
};
|
||||
use crate::model::Figurable;
|
||||
use crate::pdf::TableCellKind;
|
||||
use crate::text::LocalName;
|
||||
use crate::visualize::{Paint, Stroke};
|
||||
|
||||
@ -811,7 +811,8 @@ pub struct TableCell {
|
||||
#[fold]
|
||||
pub stroke: Sides<Option<Option<Arc<Stroke>>>>,
|
||||
|
||||
// TODO: feature gate
|
||||
#[internal]
|
||||
#[synthesized]
|
||||
pub kind: Smart<TableCellKind>,
|
||||
|
||||
/// Whether rows spanned by this cell can be placed in different pages.
|
||||
@ -851,65 +852,3 @@ impl From<Content> for TableCell {
|
||||
value.unpack::<Self>().unwrap_or_else(Self::new)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum TableCellKind {
|
||||
Header(NonZeroU32, TableHeaderScope),
|
||||
Footer,
|
||||
#[default]
|
||||
Data,
|
||||
}
|
||||
|
||||
cast! {
|
||||
TableCellKind,
|
||||
self => match self {
|
||||
Self::Header(level, scope) => dict! { "level" => level, "scope" => scope }.into_value(),
|
||||
Self::Footer => "footer".into_value(),
|
||||
Self::Data => "data".into_value(),
|
||||
},
|
||||
"header" => Self::Header(NonZeroU32::ONE, TableHeaderScope::default()),
|
||||
"footer" => Self::Footer,
|
||||
"data" => Self::Data,
|
||||
mut dict: Dict => {
|
||||
// TODO: have a `pdf.header` function instead?
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)]
|
||||
enum HeaderKind {
|
||||
Header,
|
||||
}
|
||||
dict.take("kind")?.cast::<HeaderKind>()?;
|
||||
let level = dict.take("level").ok().map(|v| v.cast()).transpose()?;
|
||||
let scope = dict.take("scope").ok().map(|v| v.cast()).transpose()?;
|
||||
dict.finish(&["kind", "level", "scope"])?;
|
||||
Self::Header(level.unwrap_or(NonZeroU32::ONE), scope.unwrap_or_default())
|
||||
},
|
||||
}
|
||||
|
||||
/// The scope of a table header cell.
|
||||
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Cast)]
|
||||
pub enum TableHeaderScope {
|
||||
/// The header cell refers to both the row and the column.
|
||||
Both,
|
||||
/// The header cell refers to the column.
|
||||
#[default]
|
||||
Column,
|
||||
/// The header cell refers to the row.
|
||||
Row,
|
||||
}
|
||||
|
||||
impl TableHeaderScope {
|
||||
pub fn refers_to_column(&self) -> bool {
|
||||
match self {
|
||||
TableHeaderScope::Both => true,
|
||||
TableHeaderScope::Column => true,
|
||||
TableHeaderScope::Row => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn refers_to_row(&self) -> bool {
|
||||
match self {
|
||||
TableHeaderScope::Both => true,
|
||||
TableHeaderScope::Column => false,
|
||||
TableHeaderScope::Row => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use ecow::EcoString;
|
||||
use typst_macros::{cast, elem, Cast};
|
||||
use typst_macros::{cast, elem, func, Cast};
|
||||
use typst_utils::NonZeroExt;
|
||||
|
||||
use crate::diag::SourceResult;
|
||||
use crate::engine::Engine;
|
||||
use crate::foundations::{Content, Packed, Show, StyleChain};
|
||||
use crate::foundations::{Content, NativeElement, Packed, Show, Smart, StyleChain};
|
||||
use crate::introspection::Locatable;
|
||||
use crate::model::TableHeaderScope;
|
||||
use crate::model::TableCell;
|
||||
|
||||
// TODO: docs
|
||||
#[elem(Locatable, Show)]
|
||||
@ -210,3 +213,68 @@ impl Show for Packed<ArtifactElem> {
|
||||
Ok(self.body.clone())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: feature gate
|
||||
/// Explicity define this cell as a header cell.
|
||||
#[func]
|
||||
pub fn header_cell(
|
||||
#[named]
|
||||
#[default(NonZeroU32::ONE)]
|
||||
level: NonZeroU32,
|
||||
#[named]
|
||||
#[default]
|
||||
scope: TableHeaderScope,
|
||||
/// The table cell.
|
||||
cell: TableCell,
|
||||
) -> Content {
|
||||
cell.with_kind(Smart::Custom(TableCellKind::Header(level, scope)))
|
||||
.pack()
|
||||
}
|
||||
|
||||
// TODO: feature gate
|
||||
/// Explicity define this cell as a data cell.
|
||||
#[func]
|
||||
pub fn data_cell(
|
||||
/// The table cell.
|
||||
cell: TableCell,
|
||||
) -> Content {
|
||||
cell.with_kind(Smart::Custom(TableCellKind::Data)).pack()
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum TableCellKind {
|
||||
Header(NonZeroU32, TableHeaderScope),
|
||||
Footer,
|
||||
#[default]
|
||||
Data,
|
||||
}
|
||||
|
||||
/// The scope of a table header cell.
|
||||
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Cast)]
|
||||
pub enum TableHeaderScope {
|
||||
/// The header cell refers to both the row and the column.
|
||||
Both,
|
||||
/// The header cell refers to the column.
|
||||
#[default]
|
||||
Column,
|
||||
/// The header cell refers to the row.
|
||||
Row,
|
||||
}
|
||||
|
||||
impl TableHeaderScope {
|
||||
pub fn refers_to_column(&self) -> bool {
|
||||
match self {
|
||||
TableHeaderScope::Both => true,
|
||||
TableHeaderScope::Column => true,
|
||||
TableHeaderScope::Row => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn refers_to_row(&self) -> bool {
|
||||
match self {
|
||||
TableHeaderScope::Both => true,
|
||||
TableHeaderScope::Column => false,
|
||||
TableHeaderScope::Row => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,5 +15,7 @@ pub fn module() -> Module {
|
||||
pdf.define_elem::<EmbedElem>();
|
||||
pdf.define_elem::<PdfTagElem>();
|
||||
pdf.define_elem::<ArtifactElem>();
|
||||
pdf.define_func::<header_cell>();
|
||||
pdf.define_func::<data_cell>();
|
||||
Module::new("pdf", pdf)
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ pub(crate) fn handle_end(gc: &mut GlobalContext, loc: Location) {
|
||||
return;
|
||||
};
|
||||
|
||||
table_ctx.insert(cell, entry.nodes);
|
||||
table_ctx.insert(&cell, entry.nodes);
|
||||
return;
|
||||
}
|
||||
StackEntryKind::Link(_, link) => {
|
||||
|
@ -7,7 +7,8 @@ use krilla::tagging::{
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
use typst_library::foundations::{Packed, Smart, StyleChain};
|
||||
use typst_library::model::{TableCell, TableCellKind, TableHeaderScope};
|
||||
use typst_library::model::TableCell;
|
||||
use typst_library::pdf::{TableCellKind, TableHeaderScope};
|
||||
|
||||
use crate::tags::{TableId, TagNode};
|
||||
|
||||
@ -54,12 +55,12 @@ impl TableCtx {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, cell: Packed<TableCell>, nodes: Vec<TagNode>) {
|
||||
pub(crate) fn insert(&mut self, cell: &TableCell, nodes: Vec<TagNode>) {
|
||||
let x = cell.x(StyleChain::default()).unwrap_or_else(|| unreachable!());
|
||||
let y = cell.y(StyleChain::default()).unwrap_or_else(|| unreachable!());
|
||||
let rowspan = cell.rowspan(StyleChain::default());
|
||||
let colspan = cell.colspan(StyleChain::default());
|
||||
let kind = cell.kind(StyleChain::default());
|
||||
let kind = cell.kind().copied().expect("kind to be set after layouting");
|
||||
|
||||
// Extend the table grid to fit this cell.
|
||||
let required_height = y + rowspan.get();
|
||||
@ -344,7 +345,7 @@ mod tests {
|
||||
fn table<const SIZE: usize>(cells: [TableCell; SIZE]) -> TableCtx {
|
||||
let mut table = TableCtx::new(TableId(324), Some("summary".into()));
|
||||
for cell in cells {
|
||||
table.insert(Packed::new(cell), Vec::new());
|
||||
table.insert(&cell, Vec::new());
|
||||
}
|
||||
table
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user