use crate::{event::Event, layout::Rect, render::Frame, style::Style};
use crossterm::event::{KeyCode, KeyEvent};
pub struct Input {
value: String,
placeholder: Option<String>,
style: Style,
cursor_style: Style,
cursor_pos: usize,
focused: bool,
on_change: Option<Box<dyn Fn(&str)>>,
}
impl Input {
pub fn new() -> Self {
Self {
value: String::new(),
placeholder: None,
style: Style::new(),
cursor_style: Style::new().reversed(),
cursor_pos: 0,
focused: false,
on_change: None,
}
}
pub fn value(mut self, value: &str) -> Self {
self.value = value.to_string();
self.cursor_pos = self.value.len();
self
}
pub fn placeholder(mut self, placeholder: &str) -> Self {
self.placeholder = Some(placeholder.to_string());
self
}
pub fn style(mut self, style: Style) -> Self {
self.style = style;
self
}
pub fn cursor_style(mut self, style: Style) -> Self {
self.cursor_style = style;
self
}
pub fn focused(mut self, focused: bool) -> Self {
self.focused = focused;
self
}
pub fn on_change<F: Fn(&str) + 'static>(mut self, f: F) -> Self {
self.on_change = Some(Box::new(f));
self
}
pub fn get_value(&self) -> &str {
&self.value
}
fn handle_key(&mut self, key: KeyEvent) {
match key.code {
KeyCode::Backspace => {
if self.cursor_pos > 0 {
self.value.remove(self.cursor_pos - 1);
self.cursor_pos -= 1;
if let Some(callback) = &self.on_change {
callback(&self.value);
}
}
}
KeyCode::Delete => {
if self.cursor_pos < self.value.len() {
self.value.remove(self.cursor_pos);
if let Some(callback) = &self.on_change {
callback(&self.value);
}
}
}
KeyCode::Left => {
if self.cursor_pos > 0 {
self.cursor_pos -= 1;
}
}
KeyCode::Right => {
if self.cursor_pos < self.value.len() {
self.cursor_pos += 1;
}
}
KeyCode::Home => {
self.cursor_pos = 0;
}
KeyCode::End => {
self.cursor_pos = self.value.len();
}
KeyCode::Char(c) => {
self.value.insert(self.cursor_pos, c);
self.cursor_pos += 1;
if let Some(callback) = &self.on_change {
callback(&self.value);
}
}
_ => {}
}
}
}
impl super::Component for Input {
fn render(&self, frame: &mut Frame, area: Rect) {
let text =
if self.value.is_empty() && self.placeholder.is_some() { self.placeholder.as_ref().unwrap() } else { &self.value };
frame.render_input(text, self.cursor_pos, area, self.style.clone(), self.cursor_style.clone(), self.focused);
}
fn handle_event(&mut self, event: &Event) -> bool {
if !self.focused {
return false;
}
match event {
Event::Key(key_event) => {
self.handle_key(*key_event);
true
}
_ => false,
}
}
}