mirror of
https://github.com/typst/typst
synced 2025-05-13 12:36:23 +08:00
Table fill closure
This commit is contained in:
parent
bc1bc91a33
commit
6536e9e069
@ -14,12 +14,9 @@ pub struct TableNode {
|
||||
|
||||
#[node(showable)]
|
||||
impl TableNode {
|
||||
/// The primary cell fill color.
|
||||
#[property(shorthand(fill))]
|
||||
pub const PRIMARY: Option<Paint> = None;
|
||||
/// The secondary cell fill color.
|
||||
#[property(shorthand(fill))]
|
||||
pub const SECONDARY: Option<Paint> = None;
|
||||
/// How to fill the cells.
|
||||
#[property(referenced)]
|
||||
pub const FILL: Celled<Option<Paint>> = Celled::Value(None);
|
||||
/// How to stroke the cells.
|
||||
#[property(resolve, fold)]
|
||||
pub const STROKE: Option<RawStroke> = Some(RawStroke::default());
|
||||
@ -71,9 +68,8 @@ impl Show for TableNode {
|
||||
}
|
||||
}
|
||||
|
||||
fn realize(&self, _: &mut Context, styles: StyleChain) -> TypResult<Content> {
|
||||
let primary = styles.get(Self::PRIMARY);
|
||||
let secondary = styles.get(Self::SECONDARY);
|
||||
fn realize(&self, ctx: &mut Context, styles: StyleChain) -> TypResult<Content> {
|
||||
let fill = styles.get(Self::FILL);
|
||||
let stroke = styles.get(Self::STROKE).map(RawStroke::unwrap_or_default);
|
||||
let padding = styles.get(Self::PADDING);
|
||||
|
||||
@ -92,13 +88,13 @@ impl Show for TableNode {
|
||||
|
||||
let x = i % cols;
|
||||
let y = i / cols;
|
||||
if let Some(fill) = [primary, secondary][(x + y) % 2] {
|
||||
if let Some(fill) = fill.resolve(ctx, x, y)? {
|
||||
child = child.filled(fill);
|
||||
}
|
||||
|
||||
child
|
||||
Ok(child)
|
||||
})
|
||||
.collect();
|
||||
.collect::<TypResult<_>>()?;
|
||||
|
||||
Ok(Content::block(GridNode {
|
||||
tracks: self.tracks.clone(),
|
||||
@ -116,3 +112,43 @@ impl Show for TableNode {
|
||||
Ok(realized.spaced(styles.get(Self::ABOVE), styles.get(Self::BELOW)))
|
||||
}
|
||||
}
|
||||
|
||||
/// A value that can be configured per cell.
|
||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||
pub enum Celled<T> {
|
||||
/// A bare value, the same for all cells.
|
||||
Value(T),
|
||||
/// A closure mapping from cell coordinates to a value.
|
||||
Func(Func, Span),
|
||||
}
|
||||
|
||||
impl<T: Cast + Clone> Celled<T> {
|
||||
/// Resolve the value based on the cell position.
|
||||
pub fn resolve(&self, ctx: &mut Context, x: usize, y: usize) -> TypResult<T> {
|
||||
Ok(match self {
|
||||
Self::Value(value) => value.clone(),
|
||||
Self::Func(func, span) => {
|
||||
let args = Args::from_values(*span, [
|
||||
Value::Int(x as i64),
|
||||
Value::Int(y as i64),
|
||||
]);
|
||||
func.call(ctx, args)?.cast().at(*span)?
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Cast> Cast<Spanned<Value>> for Celled<T> {
|
||||
fn is(value: &Spanned<Value>) -> bool {
|
||||
matches!(&value.v, Value::Func(_)) || T::is(&value.v)
|
||||
}
|
||||
|
||||
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")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
---
|
||||
#set page(height: 70pt)
|
||||
#set table(primary: rgb("aaa"), secondary: none)
|
||||
#set table(fill: (x, y) => if even(x + y) { rgb("aaa") })
|
||||
|
||||
#table(
|
||||
columns: (1fr,) * 3,
|
||||
@ -16,3 +16,7 @@
|
||||
---
|
||||
// Ref: false
|
||||
#table()
|
||||
|
||||
---
|
||||
// Error: 14-19 expected color or none or function, found string
|
||||
#table(fill: "hey")
|
||||
|
@ -26,7 +26,7 @@ Fourth
|
||||
#set par(spacing: 100pt)
|
||||
#set table(around: 5pt)
|
||||
Hello
|
||||
#table(columns: 4, secondary: silver)[A][B][C][D]
|
||||
#table(columns: 4, fill: (x, y) => if odd(x + y) { silver })[A][B][C][D]
|
||||
|
||||
---
|
||||
// While we're at it, test the larger block spacing wins.
|
||||
|
Loading…
x
Reference in New Issue
Block a user