summaryrefslogtreecommitdiff
path: root/src/library/table.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-01-17 16:01:01 +0100
committerLaurenz <laurmaedje@gmail.com>2022-01-17 16:01:01 +0100
commit0c5243fa802d8133d75c0823c3efa6f14794ba60 (patch)
treee8554c25aa9d5c3ec33c9b4d6de56f1c97d30eff /src/library/table.rs
parent4abdafcd158ab15d9d2ae18553067578ae559d33 (diff)
Basic tables
Diffstat (limited to 'src/library/table.rs')
-rw-r--r--src/library/table.rs101
1 files changed, 101 insertions, 0 deletions
diff --git a/src/library/table.rs b/src/library/table.rs
new file mode 100644
index 00000000..c8e0e17b
--- /dev/null
+++ b/src/library/table.rs
@@ -0,0 +1,101 @@
+//! Tabular container.
+
+use super::prelude::*;
+use super::{GridNode, TrackSizing};
+
+/// A table of items.
+#[derive(Debug, Hash)]
+pub struct TableNode {
+ /// Defines sizing for content rows and columns.
+ pub tracks: Spec<Vec<TrackSizing>>,
+ /// Defines sizing of gutter rows and columns between content.
+ pub gutter: Spec<Vec<TrackSizing>>,
+ /// The nodes to be arranged in the table.
+ pub children: Vec<PackedNode>,
+}
+
+#[class]
+impl TableNode {
+ /// The primary cell fill color.
+ pub const PRIMARY: Option<Paint> = None;
+ /// The secondary cell fill color.
+ pub const SECONDARY: Option<Paint> = None;
+ /// How the stroke the cells.
+ pub const STROKE: Option<Paint> = Some(RgbaColor::BLACK.into());
+ /// The stroke's thickness.
+ pub const THICKNESS: Length = Length::pt(1.0);
+ /// How much to pad the cells's content.
+ pub const PADDING: Linear = Length::pt(5.0).into();
+
+ fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
+ let columns = args.named("columns")?.unwrap_or_default();
+ let rows = args.named("rows")?.unwrap_or_default();
+ let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default();
+ let column_gutter = args.named("column-gutter")?;
+ let row_gutter = args.named("row-gutter")?;
+ Ok(Node::block(Self {
+ tracks: Spec::new(columns, rows),
+ gutter: Spec::new(
+ column_gutter.unwrap_or_else(|| base_gutter.clone()),
+ row_gutter.unwrap_or(base_gutter),
+ ),
+ children: args.all().collect(),
+ }))
+ }
+
+ fn set(args: &mut Args, styles: &mut StyleMap) -> TypResult<()> {
+ 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::THICKNESS, args.named("thickness")?);
+ styles.set_opt(Self::PADDING, args.named("padding")?);
+ Ok(())
+ }
+}
+
+impl Layout for TableNode {
+ fn layout(
+ &self,
+ ctx: &mut LayoutContext,
+ regions: &Regions,
+ styles: StyleChain,
+ ) -> Vec<Constrained<Rc<Frame>>> {
+ let primary = styles.get(Self::PRIMARY);
+ let secondary = styles.get(Self::SECONDARY);
+ let thickness = styles.get(Self::THICKNESS);
+ let stroke = styles.get(Self::STROKE).map(|paint| Stroke { paint, thickness });
+ let padding = styles.get(Self::PADDING);
+
+ let cols = self.tracks.x.len();
+ let children = self
+ .children
+ .iter()
+ .cloned()
+ .enumerate()
+ .map(|(i, mut child)| {
+ child = child.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();
+
+ let grid = GridNode {
+ tracks: self.tracks.clone(),
+ gutter: self.gutter.clone(),
+ children,
+ };
+
+ grid.layout(ctx, regions, styles)
+ }
+}