ansiq-widgets 0.1.0

Widget builders and shell-oriented UI primitives for Ansiq.
Documentation
use ansiq_core::{
    BlockFrame, Constraint, Element, ElementKind, Flex, HighlightSpacing, Layout, Length, Row,
    SelectHandler, Style, TableAlignment, TableProps, TableState, Text,
};

pub struct Table<Message = ()> {
    block: Option<BlockFrame>,
    header: Option<Row>,
    footer: Option<Row>,
    rows: Vec<Row>,
    widths: Vec<Constraint>,
    column_spacing: u16,
    flex: Flex,
    alignments: Vec<TableAlignment>,
    state: TableState,
    highlight_symbol: Option<Text>,
    row_highlight_style: Style,
    column_highlight_style: Style,
    cell_highlight_style: Style,
    highlight_spacing: HighlightSpacing,
    on_select: Option<SelectHandler<Message>>,
    layout: Layout,
    style: Style,
    focusable: bool,
}

impl<Message> Default for Table<Message> {
    fn default() -> Self {
        Self {
            block: None,
            header: None,
            footer: None,
            rows: Vec::new(),
            widths: Vec::new(),
            column_spacing: 1,
            flex: Flex::Start,
            alignments: Vec::new(),
            state: TableState::default(),
            highlight_symbol: None,
            row_highlight_style: Style::default(),
            column_highlight_style: Style::default(),
            cell_highlight_style: Style::default(),
            highlight_spacing: HighlightSpacing::WhenSelected,
            on_select: None,
            layout: Layout {
                width: Length::Fill,
                height: Length::Auto,
            },
            style: Style::default(),
            focusable: false,
        }
    }
}

impl Table<()> {
    pub fn new<R, T, C>(rows: R, widths: C) -> Self
    where
        R: IntoIterator<Item = T>,
        T: Into<Row>,
        C: IntoIterator,
        C::Item: Into<Constraint>,
    {
        Self::default().rows(rows).widths(widths)
    }
}

impl<Message> Table<Message> {
    pub fn rows<I, T>(mut self, rows: I) -> Self
    where
        I: IntoIterator<Item = T>,
        T: Into<Row>,
    {
        self.rows = rows.into_iter().map(Into::into).collect();
        self
    }

    pub fn row<T>(mut self, row: T) -> Self
    where
        T: Into<Row>,
    {
        self.rows.push(row.into());
        self
    }

    pub fn header<T>(mut self, row: T) -> Self
    where
        T: Into<Row>,
    {
        self.header = Some(row.into());
        self
    }

    pub fn headers<T>(self, row: T) -> Self
    where
        T: Into<Row>,
    {
        self.header(row)
    }

    pub fn footer<T>(mut self, row: T) -> Self
    where
        T: Into<Row>,
    {
        self.footer = Some(row.into());
        self
    }

    pub fn widths<I>(mut self, widths: I) -> Self
    where
        I: IntoIterator,
        I::Item: Into<Constraint>,
    {
        self.widths = widths.into_iter().map(Into::into).collect();
        self
    }

    pub fn column_spacing(mut self, spacing: u16) -> Self {
        self.column_spacing = spacing;
        self
    }

    pub fn flex(mut self, flex: Flex) -> Self {
        self.flex = flex;
        self
    }

    pub fn block(mut self, block: crate::Block<Message>) -> Self {
        self.block = Some(block.into_frame());
        self
    }

    pub fn selected(mut self, selected: Option<usize>) -> Self {
        self.state.select(selected);
        self
    }

    pub fn offset(mut self, offset: usize) -> Self {
        *self.state.offset_mut() = offset;
        self
    }

    pub fn state(mut self, state: TableState) -> Self {
        self.state = state;
        self
    }

    pub fn highlight_symbol<T>(mut self, symbol: T) -> Self
    where
        T: Into<Text>,
    {
        self.highlight_symbol = Some(symbol.into());
        self
    }

    pub fn highlight_style<S: Into<Style>>(self, style: S) -> Self {
        self.row_highlight_style(style)
    }

    pub fn row_highlight_style<S: Into<Style>>(mut self, style: S) -> Self {
        self.row_highlight_style = style.into();
        self
    }

    pub fn column_highlight_style<S: Into<Style>>(mut self, style: S) -> Self {
        self.column_highlight_style = style.into();
        self
    }

    pub fn cell_highlight_style<S: Into<Style>>(mut self, style: S) -> Self {
        self.cell_highlight_style = style.into();
        self
    }

    pub fn highlight_spacing(mut self, spacing: HighlightSpacing) -> Self {
        self.highlight_spacing = spacing;
        self
    }

    pub fn alignment(mut self, alignment: TableAlignment) -> Self {
        self.alignments.push(alignment);
        self
    }

    pub fn alignments<I>(mut self, alignments: I) -> Self
    where
        I: IntoIterator<Item = TableAlignment>,
    {
        self.alignments.extend(alignments);
        self
    }

    pub fn on_select<NextMessage, F>(self, handler: F) -> Table<NextMessage>
    where
        F: FnMut(usize) -> Option<NextMessage> + 'static,
    {
        Table {
            block: self.block,
            header: self.header,
            footer: self.footer,
            rows: self.rows,
            widths: self.widths,
            column_spacing: self.column_spacing,
            flex: self.flex,
            alignments: self.alignments,
            state: self.state,
            highlight_symbol: self.highlight_symbol,
            row_highlight_style: self.row_highlight_style,
            column_highlight_style: self.column_highlight_style,
            cell_highlight_style: self.cell_highlight_style,
            highlight_spacing: self.highlight_spacing,
            on_select: Some(std::boxed::Box::new(handler)),
            layout: self.layout,
            style: self.style,
            focusable: true,
        }
    }

    pub fn layout(mut self, layout: Layout) -> Self {
        self.layout = layout;
        self
    }

    pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
        self.style = style.into();
        self
    }

    pub fn build(self) -> Element<Message> {
        Element::new(ElementKind::Table(TableProps {
            block: self.block,
            header: self.header,
            footer: self.footer,
            rows: self.rows,
            widths: self.widths,
            column_spacing: self.column_spacing,
            flex: self.flex,
            alignments: self.alignments,
            state: self.state,
            highlight_symbol: self.highlight_symbol,
            row_highlight_style: self.row_highlight_style,
            column_highlight_style: self.column_highlight_style,
            cell_highlight_style: self.cell_highlight_style,
            highlight_spacing: self.highlight_spacing,
            on_select: self.on_select,
        }))
        .with_layout(self.layout)
        .with_style(self.style)
        .with_focusable(self.focusable)
    }
}

impl<Item> FromIterator<Item> for Table<()>
where
    Item: Into<Row>,
{
    fn from_iter<Iter: IntoIterator<Item = Item>>(iter: Iter) -> Self {
        Self::default().rows(iter)
    }
}