use std::io;
use textwrap::{core::Fragment, WordSeparator};
use crate::{backend::Backend, events::KeyEvent, layout::Layout};
pub use crate::char_input::CharInput;
pub use crate::prompt::{Delimiter, Prompt};
pub use crate::select::{List, Select};
pub use crate::string_input::StringInput;
pub use crate::text::Text;
pub type FilterMapChar = fn(char) -> Option<char>;
pub(crate) fn no_filter(c: char) -> Option<char> {
Some(c)
}
pub trait Widget {
fn render<B: Backend>(&mut self, layout: &mut Layout, backend: &mut B) -> io::Result<()>;
fn height(&mut self, layout: &mut Layout) -> u16;
fn cursor_pos(&mut self, layout: Layout) -> (u16, u16);
fn handle_key(&mut self, key: KeyEvent) -> bool;
}
impl<T: std::ops::Deref<Target = str> + ?Sized> Widget for T {
fn render<B: Backend>(&mut self, layout: &mut Layout, backend: &mut B) -> io::Result<()> {
let max_width = layout.line_width() as usize;
layout.offset_y += 1;
layout.line_offset = 0;
if max_width <= 3 {
for _ in 0..max_width {
backend.write_all(b".")?;
}
} else if textwrap::core::display_width(self) > max_width {
let mut width = 0;
let mut prev_whitespace_len = 0;
let max_width = max_width - 3;
for word in WordSeparator::UnicodeBreakProperties.find_words(self) {
width += word.width() as usize + prev_whitespace_len;
if width > max_width {
break;
}
for _ in 0..prev_whitespace_len {
backend.write_all(b" ")?;
}
backend.write_all(word.as_bytes())?;
prev_whitespace_len = word.whitespace_width() as usize;
}
backend.write_all(b"...")?;
} else {
backend.write_all(self.as_bytes())?;
}
backend.move_cursor_to(layout.offset_x, layout.offset_y)
}
fn height(&mut self, layout: &mut Layout) -> u16 {
layout.offset_y += 1;
layout.line_offset = 0;
1
}
fn cursor_pos(&mut self, layout: Layout) -> (u16, u16) {
layout.offset_cursor((layout.line_offset, 0))
}
fn handle_key(&mut self, _: crate::events::KeyEvent) -> bool {
false
}
}