use super::{PropMap, PropValue};
use crate::View;
use crate::derive_support::PlushieType;
use crate::types::*;
pub struct TableColumnSpec {
key: String,
label: Option<String>,
width: Option<Length>,
min_width: Option<f32>,
sortable: bool,
align: Option<HorizontalAlignment>,
}
impl TableColumnSpec {
fn new(key: &str) -> Self {
Self {
key: key.to_string(),
label: None,
width: None,
min_width: None,
sortable: false,
align: None,
}
}
pub fn label(mut self, label: &str) -> Self {
self.label = Some(label.to_string());
self
}
pub fn width(mut self, w: impl Into<Length>) -> Self {
self.width = Some(w.into());
self
}
pub fn min_width(mut self, px: f32) -> Self {
self.min_width = Some(px);
self
}
pub fn sortable(mut self, v: bool) -> Self {
self.sortable = v;
self
}
pub fn align(mut self, a: HorizontalAlignment) -> Self {
self.align = Some(a);
self
}
fn to_prop_value(&self) -> PropValue {
let mut m = PropMap::new();
m.insert("key", PropValue::Str(self.key.clone()));
m.insert(
"label",
PropValue::Str(self.label.as_deref().unwrap_or(&self.key).to_string()),
);
if let Some(ref w) = self.width {
m.insert("width", w.wire_encode());
}
if let Some(mw) = self.min_width {
m.insert("min_width", PropValue::F64(mw as f64));
}
if self.sortable {
m.insert("sortable", PropValue::Bool(true));
}
if let Some(ref a) = self.align {
m.insert("align", a.wire_encode());
}
PropValue::Object(m)
}
}
pub struct TableRowBuilder {
id: String,
cells: Vec<(String, View)>,
}
impl TableRowBuilder {
fn new(id: &str) -> Self {
Self {
id: id.to_string(),
cells: Vec::new(),
}
}
pub fn cell(mut self, column_key: &str, content: impl Into<View>) -> Self {
self.cells.push((column_key.to_string(), content.into()));
self
}
fn into_view(self) -> View {
let children: Vec<View> = self
.cells
.into_iter()
.map(|(col_key, content)| {
let mut cell_props = PropMap::new();
cell_props.insert("column", PropValue::Str(col_key.clone()));
super::view_node(col_key, "table_cell", cell_props, vec![content])
})
.collect();
super::view_node(self.id, "table_row", PropMap::new(), children)
}
}
pub struct TableBuilder {
id: String,
props: PropMap,
column_specs: Vec<TableColumnSpec>,
children: Vec<View>,
}
pub fn table(id: &str) -> TableBuilder {
TableBuilder {
id: id.to_string(),
props: PropMap::new(),
column_specs: Vec::new(),
children: vec![],
}
}
impl TableBuilder {
pub fn column(mut self, key: &str, f: impl FnOnce(TableColumnSpec) -> TableColumnSpec) -> Self {
self.column_specs.push(f(TableColumnSpec::new(key)));
self
}
pub fn columns(mut self, cols: &[(&str, &str)]) -> Self {
for &(key, label) in cols {
self.column_specs
.push(TableColumnSpec::new(key).label(label));
}
self
}
pub fn row(mut self, id: &str, f: impl FnOnce(TableRowBuilder) -> TableRowBuilder) -> Self {
self.children.push(f(TableRowBuilder::new(id)).into_view());
self
}
pub fn data_row(mut self, id: &str, cells: &[(&str, &str)]) -> Self {
let row_children: Vec<View> = cells
.iter()
.map(|&(col_key, value)| {
let mut cell_props = PropMap::new();
cell_props.insert("column", PropValue::Str(col_key.to_string()));
let text_view = super::view_leaf(format!("{id}/{col_key}/text"), "text", {
let mut p = PropMap::new();
p.insert("content", PropValue::Str(value.to_string()));
p
});
super::view_node(
col_key.to_string(),
"table_cell",
cell_props,
vec![text_view],
)
})
.collect();
self.children.push(super::view_node(
id.to_string(),
"table_row",
PropMap::new(),
row_children,
));
self
}
pub fn width(mut self, w: impl Into<Length>) -> Self {
super::set_prop(&mut self.props, "width", super::length_to_value(w.into()));
self
}
pub fn height(mut self, h: impl Into<Length>) -> Self {
super::set_prop(&mut self.props, "height", super::length_to_value(h.into()));
self
}
pub fn header(mut self, v: bool) -> Self {
super::set_prop(&mut self.props, "header", v);
self
}
pub fn sort_by(mut self, column: &str) -> Self {
super::set_prop(&mut self.props, "sort_by", column);
self
}
pub fn sort_order(mut self, order: SortOrder) -> Self {
super::set_prop(&mut self.props, "sort_order", order.wire_encode());
self
}
pub fn separator(mut self, thickness: f32) -> Self {
super::set_prop(&mut self.props, "separator", thickness);
self
}
pub fn padding(mut self, p: impl Into<Padding>) -> Self {
super::set_prop(
&mut self.props,
"padding",
super::padding_to_value(p.into()),
);
self
}
pub fn header_text_size(mut self, s: impl Into<Animatable<f32>>) -> Self {
super::set_prop(&mut self.props, "header_text_size", s.into().wire_encode());
self
}
pub fn row_text_size(mut self, s: impl Into<Animatable<f32>>) -> Self {
super::set_prop(&mut self.props, "row_text_size", s.into().wire_encode());
self
}
pub fn event_rate(mut self, rate: u32) -> Self {
super::set_prop(&mut self.props, "event_rate", rate);
self
}
pub fn a11y(mut self, a11y: &A11y) -> Self {
super::set_prop(&mut self.props, "a11y", a11y.wire_encode());
self
}
}
impl From<TableBuilder> for View {
fn from(mut b: TableBuilder) -> View {
if !b.column_specs.is_empty() {
let cols: Vec<PropValue> = b.column_specs.iter().map(|c| c.to_prop_value()).collect();
b.props.insert("columns", PropValue::Array(cols));
}
super::view_node(b.id, "table", b.props, b.children)
}
}