1use crate::element::Element;
7use crate::style::{Align, Border, Color, Common};
8
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]
14#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
15#[derive(Clone, Copy, Debug)]
16pub enum ColumnWidth {
17 Fixed(f32),
18 Flex(f32),
19}
20
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(deny_unknown_fields))]
22#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
23#[derive(Clone, Copy, Debug)]
24pub struct TableColumn {
25 pub width: ColumnWidth,
26 #[cfg_attr(feature = "serde", serde(default))]
27 pub align: Align,
28}
29
30impl TableColumn {
31 pub fn fixed(width: f32) -> Self {
32 TableColumn {
33 width: ColumnWidth::Fixed(width),
34 align: Align::Start,
35 }
36 }
37
38 pub fn flex(weight: f32) -> Self {
39 TableColumn {
40 width: ColumnWidth::Flex(weight),
41 align: Align::Start,
42 }
43 }
44
45 pub fn align(mut self, align: Align) -> Self {
46 self.align = align;
47 self
48 }
49}
50
51#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(deny_unknown_fields))]
52#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
53#[derive(Clone, Debug)]
54pub struct TableCell {
55 pub element: Element,
56 #[cfg_attr(feature = "serde", serde(default = "TableCell::default_span"))]
57 pub colspan: usize,
58 #[cfg_attr(feature = "serde", serde(default = "TableCell::default_span"))]
64 pub rowspan: usize,
65 #[cfg_attr(feature = "serde", serde(default))]
66 pub align: Option<Align>,
67 #[cfg_attr(feature = "serde", serde(default))]
71 pub background: Option<Color>,
72 #[cfg_attr(feature = "serde", serde(default))]
73 pub border: Option<Border>,
74 #[cfg_attr(feature = "serde", serde(default))]
76 pub padding: Option<f32>,
77}
78
79impl TableCell {
80 pub fn new(element: impl Into<Element>) -> Self {
81 TableCell {
82 element: element.into(),
83 colspan: 1,
84 rowspan: 1,
85 align: None,
86 background: None,
87 border: None,
88 padding: None,
89 }
90 }
91
92 #[cfg(feature = "serde")]
93 fn default_span() -> usize {
94 1
95 }
96
97 pub fn colspan(mut self, colspan: usize) -> Self {
98 self.colspan = colspan.max(1);
99 self
100 }
101
102 pub fn rowspan(mut self, rowspan: usize) -> Self {
103 self.rowspan = rowspan.max(1);
104 self
105 }
106
107 pub fn align(mut self, align: Align) -> Self {
108 self.align = Some(align);
109 self
110 }
111
112 pub fn background(mut self, color: Color) -> Self {
113 self.background = Some(color);
114 self
115 }
116
117 pub fn border(mut self, border: Border) -> Self {
118 self.border = Some(border);
119 self
120 }
121
122 pub fn padding(mut self, padding: f32) -> Self {
123 self.padding = Some(padding);
124 self
125 }
126}
127
128impl<T: Into<Element>> From<T> for TableCell {
129 fn from(value: T) -> Self {
130 TableCell::new(value)
131 }
132}
133
134pub trait TableRow {
141 fn cells(&self) -> Vec<TableCell>;
142}
143
144#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(deny_unknown_fields))]
145#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
146#[derive(Clone, Debug, Default)]
147pub struct Table {
148 #[cfg_attr(feature = "serde", serde(default))]
149 pub columns: Vec<TableColumn>,
150 #[cfg_attr(feature = "serde", serde(default))]
151 pub header: Option<Vec<TableCell>>,
152 #[cfg_attr(feature = "serde", serde(default))]
153 pub rows: Vec<Vec<TableCell>>,
154 #[cfg_attr(feature = "serde", serde(default))]
158 pub striped: Option<Color>,
159 #[cfg_attr(feature = "serde", serde(default = "Table::default_cell_padding"))]
162 pub cell_padding: f32,
163 #[cfg_attr(feature = "serde", serde(skip))]
169 pub row_offset: usize,
170 #[cfg_attr(feature = "serde", serde(default))]
171 pub common: Common,
172}
173
174impl Table {
175 #[cfg(feature = "serde")]
176 fn default_cell_padding() -> f32 {
177 Table::new().cell_padding
178 }
179
180 pub fn new() -> Self {
181 Table {
182 cell_padding: 4.0,
183 ..Default::default()
184 }
185 }
186
187 pub fn columns(mut self, columns: impl IntoIterator<Item = TableColumn>) -> Self {
188 self.columns = columns.into_iter().collect();
189 self
190 }
191
192 pub fn header(mut self, cells: impl IntoIterator<Item = impl Into<TableCell>>) -> Self {
193 self.header = Some(cells.into_iter().map(Into::into).collect());
194 self
195 }
196
197 pub fn rows(mut self, rows: impl IntoIterator<Item = impl IntoIterator<Item = impl Into<TableCell>>>) -> Self {
198 self.rows = rows.into_iter().map(|row| row.into_iter().map(Into::into).collect()).collect();
199 self
200 }
201
202 pub fn from_rows<T: TableRow>(mut self, items: &[T]) -> Self {
205 self.rows = items.iter().map(TableRow::cells).collect();
206 self
207 }
208
209 pub fn striped(mut self, color: Color) -> Self {
210 self.striped = Some(color);
211 self
212 }
213
214 pub fn cell_padding(mut self, padding: f32) -> Self {
215 self.cell_padding = padding;
216 self
217 }
218
219 pub fn width(mut self, width: f32) -> Self {
220 self.common.width = Some(width);
221 self
222 }
223
224 pub fn height(mut self, height: f32) -> Self {
225 self.common.height = Some(height);
226 self
227 }
228
229 pub fn flex(mut self, factor: f32) -> Self {
230 self.common.flex = Some(factor);
231 self
232 }
233
234 pub fn keep_with_next(mut self) -> Self {
235 self.common.keep_with_next = true;
236 self
237 }
238}