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,
);
}
if state
.input
.is_empty()
{
Paragraph::new("")
.style(
Style::new().bg(
self.style
.bg
.unwrap_or_default(),
),
)
.render(
area, buf,
);
}
else
{
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 line = Line::from(
vec![
Span::styled(
before,
Style::new().fg(
self.style
.fg
.unwrap_or_default(),
),
),
Span::styled(
&state.placeholder, Style::new().dark_gray(),
),
Span::styled(
after,
Style::new().fg(
self.style
.fg
.unwrap_or_default(),
),
),
],
);
Paragraph::new(line)
.style(
Style::new().bg(
self.style
.bg
.unwrap_or_default(),
),
)
.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;
}
}