use crate::library::layout::{GridNode, TrackSizing}; use crate::library::prelude::*; /// A table of items. #[derive(Debug, Hash)] pub struct TableNode { /// Defines sizing for content rows and columns. pub tracks: Spec>, /// Defines sizing of gutter rows and columns between content. pub gutter: Spec>, /// The nodes to be arranged in the table. pub cells: Vec, } #[node(showable)] impl TableNode { /// The primary cell fill color. pub const PRIMARY: Option = None; /// The secondary cell fill color. pub const SECONDARY: Option = None; /// How to stroke the cells. #[property(resolve, fold)] pub const STROKE: Option = Some(RawStroke::default()); /// How much to pad the cells's content. pub const PADDING: Relative = Length::pt(5.0).into(); fn construct(_: &mut Context, args: &mut Args) -> TypResult { let columns = args.named("columns")?.unwrap_or_default(); let rows = args.named("rows")?.unwrap_or_default(); let base_gutter: Vec = args.named("gutter")?.unwrap_or_default(); let column_gutter = args.named("column-gutter")?; let row_gutter = args.named("row-gutter")?; Ok(Content::show(Self { tracks: Spec::new(columns, rows), gutter: Spec::new( column_gutter.unwrap_or_else(|| base_gutter.clone()), row_gutter.unwrap_or(base_gutter), ), cells: args.all()?, })) } fn set(args: &mut Args) -> TypResult { let mut styles = StyleMap::new(); let fill = args.named("fill")?; styles.set_opt(Self::PRIMARY, args.named("primary")?.or(fill)); styles.set_opt(Self::SECONDARY, args.named("secondary")?.or(fill)); styles.set_opt(Self::STROKE, args.named("stroke")?); styles.set_opt(Self::PADDING, args.named("padding")?); Ok(styles) } } impl Show for TableNode { fn encode(&self) -> Dict { dict! { "cells" => Value::Array( self.cells .iter() .map(|cell| Value::Content(cell.clone())) .collect() ), } } fn realize(&self, _: &mut Context, styles: StyleChain) -> TypResult { let primary = styles.get(Self::PRIMARY); let secondary = styles.get(Self::SECONDARY); let stroke = styles.get(Self::STROKE).map(RawStroke::unwrap_or_default); let padding = styles.get(Self::PADDING); let cols = self.tracks.x.len().max(1); let cells = self .cells .iter() .cloned() .enumerate() .map(|(i, child)| { let mut child = child.pack().padded(Sides::splat(padding)); if let Some(stroke) = stroke { child = child.stroked(stroke); } let x = i % cols; let y = i / cols; if let Some(fill) = [primary, secondary][(x + y) % 2] { child = child.filled(fill); } child }) .collect(); Ok(Content::block(GridNode { tracks: self.tracks.clone(), gutter: self.gutter.clone(), cells, })) } }