diff --git a/src/key.rs b/src/key.rs index 0aafd8f..a33e9ea 100644 --- a/src/key.rs +++ b/src/key.rs @@ -1,3 +1,8 @@ pub const ENTER: &str = "\r"; pub const TAB: &str = "\t"; pub const BACKSPACE: &str = "\u{7f}"; +pub const ESC: &str = "\u{1b}"; +pub const UP: &str = "\u{1b}[A"; +pub const DOWN: &str = "\u{1b}[B"; +pub const RIGHT: &str = "\u{1b}[C"; +pub const LEFT: &str = "\u{1b}[D"; diff --git a/src/lib.rs b/src/lib.rs index 80d07b5..e22e70c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,20 +6,23 @@ use std::{ pub mod key; pub mod ui; -#[derive(Clone)] +#[derive(Clone, Copy)] pub struct ComponentWrapper { - pub component: T, + pub contents: T, pub x: usize, pub y: usize, + update_fn: fn(&mut T) -> bool, } pub trait Component { fn render(&self) -> String { String::new() } - fn run(&mut self, x: usize, y: usize) -> String { + + fn run(&mut self, x: usize, y: usize, update_fn: fn(&mut Self) -> bool) -> String { let _ = x; let _ = y; + let _ = update_fn; String::new() } } @@ -27,19 +30,23 @@ pub trait Component { impl ComponentWrapper { pub fn new(component: T) -> ComponentWrapper { ComponentWrapper { - component, + contents: component, x: 0, y: 0, + update_fn: (|_| false), } } pub fn run(&mut self) -> String { - self.component.run(self.x, self.y) + self.contents.run(self.x, self.y, self.update_fn) } pub fn render(&self, frame: &mut Vec) { - for (i, line) in self.component.render().split("\n").enumerate() { + for (i, line) in self.contents.render().split("\n").enumerate() { frame[self.y + i] = _render_line(frame[self.y + i].clone(), line.to_string(), self.x); } } + pub fn update(&mut self, update_fn: fn(&mut T) -> bool) { + self.update_fn = update_fn; + } } pub fn clear() { diff --git a/src/ui.rs b/src/ui.rs index 2f56677..a9cc5fd 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -12,6 +12,8 @@ pub fn text(text: &str) -> ComponentWrapper { #[derive(Clone)] pub struct Input { pub max_length: usize, + pub key: String, + pub data: String, } impl Component for Input { @@ -23,35 +25,41 @@ impl Component for Input { "‾".repeat(self.max_length), ) } - fn run(&mut self, x: usize, y: usize) -> String { + fn run(&mut self, x: usize, y: usize, update_fn: fn(&mut Self) -> bool) -> String { print!("\x1B[{};{}H", y + 2, x + 2); flush(); - let mut input = String::new(); loop { - match read_key().as_str() { - key::ENTER => { - print!("\n\n"); - return input; - } + self.key = read_key(); + if update_fn(self) { + break; + } + match self.key.as_str() { + key::ENTER => break, key::BACKSPACE => { - if input.len() > 0 { - input.pop(); + if self.data.len() > 0 { + self.data.pop(); print!("\x1b[1D \x1b[1D"); flush(); } } c => { - if input.len() < self.max_length { - input += c.to_string().as_str(); + if self.data.len() < self.max_length { + self.data += c.to_string().as_str(); print!("{c}"); flush(); } } } } + print!("\n\n"); + return self.data.clone(); } } pub fn input_box(max_length: usize) -> ComponentWrapper { - ComponentWrapper::new(Input { max_length }) + ComponentWrapper::new(Input { + max_length, + key: String::new(), + data: String::new(), + }) }