ansiq-widgets 0.1.0

Widget builders and shell-oriented UI primitives for Ansiq.
Documentation
use ansiq_core::{
    BlockFrame, Element, ElementKind, HighlightSpacing, Layout, Length, Line, ListDirection,
    ListItem, ListProps, ListState, SelectHandler, Style,
};

use crate::Block;

pub struct List<Message = ()> {
    block: Option<BlockFrame>,
    items: Vec<ListItem>,
    state: ListState,
    highlight_symbol: Option<Line>,
    highlight_style: Style,
    highlight_spacing: HighlightSpacing,
    repeat_highlight_symbol: bool,
    direction: ListDirection,
    scroll_padding: usize,
    on_select: Option<SelectHandler<Message>>,
    layout: Layout,
    style: Style,
    focusable: bool,
}

impl<Message> Default for List<Message> {
    fn default() -> Self {
        Self {
            block: None,
            items: Vec::new(),
            state: ListState::default(),
            highlight_symbol: None,
            highlight_style: Style::default(),
            highlight_spacing: HighlightSpacing::WhenSelected,
            repeat_highlight_symbol: false,
            direction: ListDirection::TopToBottom,
            scroll_padding: 0,
            on_select: None,
            layout: Layout {
                width: Length::Fill,
                height: Length::Auto,
            },
            style: Style::default(),
            focusable: false,
        }
    }
}

impl List<()> {
    pub fn new<I, T>(items: I) -> Self
    where
        I: IntoIterator<Item = T>,
        T: Into<ListItem>,
    {
        Self::default().items(items)
    }
}

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

    pub fn item<T>(mut self, item: T) -> Self
    where
        T: Into<ListItem>,
    {
        self.items.push(item.into());
        self
    }

    pub fn items<I, T>(mut self, items: I) -> Self
    where
        I: IntoIterator<Item = T>,
        T: Into<ListItem>,
    {
        self.items = items.into_iter().map(Into::into).collect();
        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: ListState) -> Self {
        self.state = state;
        self
    }

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

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

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

    pub fn repeat_highlight_symbol(mut self, repeat: bool) -> Self {
        self.repeat_highlight_symbol = repeat;
        self
    }

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

    pub fn scroll_padding(mut self, padding: usize) -> Self {
        self.scroll_padding = padding;
        self
    }

    pub fn on_select<NextMessage, F>(self, handler: F) -> List<NextMessage>
    where
        F: FnMut(usize) -> Option<NextMessage> + 'static,
    {
        List {
            block: self.block,
            items: self.items,
            state: self.state,
            highlight_symbol: self.highlight_symbol,
            highlight_style: self.highlight_style,
            highlight_spacing: self.highlight_spacing,
            repeat_highlight_symbol: self.repeat_highlight_symbol,
            direction: self.direction,
            scroll_padding: self.scroll_padding,
            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 len(&self) -> usize {
        self.items.len()
    }

    pub fn is_empty(&self) -> bool {
        self.items.is_empty()
    }

    pub fn build(self) -> Element<Message> {
        Element::new(ElementKind::List(ListProps {
            block: self.block,
            items: self.items,
            state: self.state,
            highlight_symbol: self.highlight_symbol,
            highlight_style: self.highlight_style,
            highlight_spacing: self.highlight_spacing,
            repeat_highlight_symbol: self.repeat_highlight_symbol,
            direction: self.direction,
            scroll_padding: self.scroll_padding,
            on_select: self.on_select,
        }))
        .with_layout(self.layout)
        .with_style(self.style)
        .with_focusable(self.focusable)
    }
}

impl<Item> FromIterator<Item> for List<()>
where
    Item: Into<ListItem>,
{
    fn from_iter<Iter: IntoIterator<Item = Item>>(iter: Iter) -> Self {
        Self::new(iter)
    }
}