rtlibs-tui 0.1.4

rtools library: ratatui widgets
Documentation
use ratatui::buffer::Buffer;
use ratatui::layout::Alignment;
use ratatui::layout::Constraint;
use ratatui::layout::Layout;
use ratatui::layout::Rect;
use ratatui::style::Style;
use ratatui::style::Stylize;
use ratatui::text::Line;
use ratatui::text::Span;
use ratatui::text::Text;
use ratatui::widgets::Clear;
use ratatui::widgets::Paragraph;
use ratatui::widgets::StatefulWidget;
use ratatui::widgets::Widget;

use super::InputState;

pub struct InputWidget
{
    pub style: Style,
}

impl std::default::Default for InputWidget
{
    fn default() -> Self
    {
        Self::new()
    }
}

impl InputWidget
{
    pub fn new() -> Self
    {
        Self {
            style: Style::default(),
        }
    }

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

impl StatefulWidget for InputWidget
{
    type State = InputState;

    fn render(
        self,
        area: Rect,
        buf: &mut Buffer,
        state: &mut Self::State,
    )
    {
        Clear.render(
            area, buf,
        );

        let label_length = if let Some(label) = state.label()
        {
            label
                .chars()
                .count()
        }
        else
        {
            0
        };

        let [label_area, area] =
            Layout::horizontal([Constraint::Length(label_length as u16), Constraint::Fill(1)])
                .areas(area);

        if let Some(label) = state.label()
        {
            Text::raw(label).render(
                label_area, buf,
            );
        }

        // let line = if let Some(placeholder) = state
        //     .placeholder
        //     .as_ref()
        // {
        //

        if state
            .input
            .is_empty()
        {
            Paragraph::new("")
                .style(
                    Style::new().bg(
                        self.style
                            .bg
                            .unwrap_or_default(),
                    ),
                )
                .render(
                    area, buf,
                );
        }
        else
        {
            // let mut index = state.character_index;
            // if index
            //     == state
            //         .input
            //         .chars()
            //         .count()
            // {
            //     index -= 1;
            // }
            let (index, _) = state
                .input
                .char_indices()
                .nth(state.character_index)
                .unwrap_or((
                    state
                        .input
                        .len(),
                    ' ',
                ));
            let before = &state.input[0..index];
            let after = if index
                == state
                    .input
                    .len()
            {
                ""
            }
            else
            {
                &state.input[index..]
            };
            // let after = &state.input[index..];

            let line = Line::from(
                vec![
                    Span::styled(
                        before,
                        Style::new().fg(
                            self.style
                                .fg
                                .unwrap_or_default(),
                        ),
                    ),
                    Span::styled(
                        // "--",
                        &state.placeholder, // .clone()
                        Style::new().dark_gray(),
                    ),
                    Span::styled(
                        after,
                        Style::new().fg(
                            self.style
                                .fg
                                .unwrap_or_default(),
                        ),
                    ),
                ],
            );
            // }
            // else
            // {
            //     Line::styled(
            //         state
            //             .input
            //             .clone(),
            //         Style::new().fg(
            //             self.style
            //                 .fg
            //                 .unwrap_or_default(),
            //         ),
            //     )
            // };

            Paragraph::new(line)
                .style(
                    Style::new().bg(
                        self.style
                            .bg
                            .unwrap_or_default(),
                    ),
                )
                // .style(self.style)
                .alignment(
                    if state.right_aligned
                    {
                        Alignment::Right
                    }
                    else
                    {
                        Alignment::Left
                    },
                )
                .render(
                    area, buf,
                );
        }

        if state.right_aligned
        {
            state
                .cursor
                .x = area.x + area.width
                - state
                    .input
                    .chars()
                    .count() as u16
                + state.character_index as u16;
        }
        else
        {
            state
                .cursor
                .x = area.x + state.character_index as u16;
        }
        state
            .cursor
            .y = area.y;
    }
}