use animaterm::{prelude::*, utilities::message_box}; fn main() { let mut mgr = Manager::new(true, None, None, None, None, None); let mut input = Input::new(&mut mgr); input.show(&mut mgr); loop { if let Some(ch) = mgr.read_char() { if let Some(key) = map_private_char_to_key(ch) { match key { Key::Up => input.move_cursor(Direction::Up, &mut mgr), Key::Down => input.move_cursor(Direction::Down, &mut mgr), Key::Left => input.move_cursor(Direction::Left, &mut mgr), Key::Right => input.move_cursor(Direction::Right, &mut mgr), Key::Home => input.move_to_line_start(&mut mgr), Key::End => input.move_to_line_end(&mut mgr), Key::Delete => input.delete(&mut mgr), Key::AltB => { input.move_cursor(Direction::Left, &mut mgr); input.move_cursor(Direction::Left, &mut mgr); input.move_cursor(Direction::Left, &mut mgr); input.move_cursor(Direction::Left, &mut mgr); } Key::AltF => { input.move_cursor(Direction::Right, &mut mgr); input.move_cursor(Direction::Right, &mut mgr); input.move_cursor(Direction::Right, &mut mgr); input.move_cursor(Direction::Right, &mut mgr); } Key::AltQ => input.toggle_style(Style::Bright, &mut mgr), Key::AltW => input.toggle_style(Style::Transparent, &mut mgr), Key::AltE => input.toggle_style(Style::Italic, &mut mgr), Key::AltR => input.toggle_style(Style::Underline, &mut mgr), Key::AltT => input.toggle_style(Style::Blink, &mut mgr), Key::AltY => input.toggle_style(Style::Blinkfast, &mut mgr), Key::AltU => input.toggle_style(Style::Reverse, &mut mgr), Key::AltI => input.toggle_style(Style::Strike, &mut mgr), _other => {} } } else if ch == '\u{1b}' { break; } else if ch == '\u{7f}' { input.backspace(&mut mgr); } else if ch == '\u{1}' { input.move_to_line_start(&mut mgr); } else if ch == '\u{5}' { input.move_to_line_end(&mut mgr); } else if ch == '\u{a}' { input.move_cursor(Direction::Down, &mut mgr); input.move_to_line_start(&mut mgr); } else if ch == '\u{b}' { input.remove_chars_from_cursor_to_end(&mut mgr); } else if ch == '\u{e}' { input.move_cursor(Direction::Down, &mut mgr); } else if ch == '\u{10}' { input.move_cursor(Direction::Up, &mut mgr); } else if ch == '\u{2}' { input.move_cursor(Direction::Left, &mut mgr); } else if ch == '\u{6}' { input.move_cursor(Direction::Right, &mut mgr); } else { input.insert(&mut mgr, ch); } } } mgr.terminate(); } pub struct Input { pub g_id: usize, text: Vec, cursor_position: (usize, usize), max_position: (usize, usize), } impl Input { pub fn new(mgr: &mut Manager) -> Self { let (cols, rows) = mgr.screen_size(); let m_box = message_box( Some( "Type in text, ESC: exit, Alt+[Q|W|E|R|T|Y|U|I]: modify selected char".to_string(), ), String::new(), Glyph::plain(), cols, rows, ); let g_id = mgr.add_graphic(m_box, 0, (0, 0)).unwrap(); Input { g_id, text: vec![String::new(); rows], cursor_position: (2, 1), max_position: (cols - 2, rows - 2), } } pub fn show(&mut self, mgr: &mut Manager) { mgr.move_graphic(self.g_id, 2, (0, 0)); mgr.set_graphic(self.g_id, 0, true); } pub fn hide(&mut self, mgr: &mut Manager) { mgr.move_graphic(self.g_id, 0, (0, 0)); } pub fn insert(&mut self, mgr: &mut Manager, ch: char) { let len = self.text[self.cursor_position.1].chars().count(); if len >= self.max_position.0 - 2 { return; } let glyph = if ch == '\n' { Glyph::plain() } else { Glyph::char(ch) }; if self.cursor_position.0 - 2 == len { self.text[self.cursor_position.1].push(ch); } else { let mut chars = self.text[self.cursor_position.1].chars(); let mut new_string = String::with_capacity(len); for _i in 0..self.cursor_position.0 - 2 { if let Some(char) = chars.next() { new_string.push(char); } else { new_string.push(' '); } } new_string.push(ch); let mut i = 1; for char in chars { new_string.push(char); mgr.set_glyph( self.g_id, Glyph::char(char), i + self.cursor_position.0, self.cursor_position.1, ); i += 1; } self.text[self.cursor_position.1] = new_string; } mgr.set_glyph( self.g_id, glyph, self.cursor_position.0, self.cursor_position.1, ); if ch == '\n' { if self.cursor_position.1 < self.max_position.1 { self.cursor_position.0 = 2; self.cursor_position.1 += 1; } } else { self.cursor_position.0 += 1; if self.cursor_position.0 > self.max_position.0 { self.cursor_position.0 = 2; self.cursor_position.1 += 1; if self.cursor_position.1 > self.max_position.1 { self.cursor_position.1 = self.max_position.1; } } } mgr.get_glyph(self.g_id, self.cursor_position.0, self.cursor_position.1); if let Ok(AnimOk::GlyphRetrieved(_u, mut glyph)) = mgr.read_result() { glyph.set_blink(true); glyph.set_reverse(true); mgr.set_glyph( self.g_id, glyph, self.cursor_position.0, self.cursor_position.1, ); } } pub fn backspace(&mut self, mgr: &mut Manager) { let glyph = Glyph::plain(); let mut last_char = false; let len = self.text[self.cursor_position.1].chars().count(); match len.cmp(&(self.cursor_position.0 - 2)) { std::cmp::Ordering::Less => {} std::cmp::Ordering::Equal => { mgr.set_glyph( self.g_id, glyph, self.cursor_position.0, self.cursor_position.1, ); last_char = true; self.text[self.cursor_position.1].pop(); mgr.set_glyph( self.g_id, Glyph::plain(), self.cursor_position.0, self.cursor_position.1, ); } std::cmp::Ordering::Greater => { if self.cursor_position.0 == 2 { return; } mgr.set_glyph( self.g_id, glyph, self.cursor_position.0, self.cursor_position.1, ); let mut chars = self.text[self.cursor_position.1].chars(); let mut new_string = String::with_capacity(len); for _i in 0..self.cursor_position.0 - 3 { if let Some(char) = chars.next() { new_string.push(char); } } let _skip = chars.next(); let mut i = 0; for char in chars { new_string.push(char); mgr.set_glyph( self.g_id, Glyph::char(char), self.cursor_position.0 + i - 1, self.cursor_position.1, ); i += 1; } self.text[self.cursor_position.1] = new_string; mgr.set_glyph( self.g_id, Glyph::plain(), self.cursor_position.0 + i - 1, self.cursor_position.1, ); } } self.cursor_position.0 -= 1; if self.cursor_position.0 < 2 { self.cursor_position.1 -= 1; if self.cursor_position.1 == 0 { self.cursor_position = (2, 1); } else { self.cursor_position.0 = self.text[self.cursor_position.1].chars().count() + 2; } } mgr.get_glyph(self.g_id, self.cursor_position.0, self.cursor_position.1); if let Ok(AnimOk::GlyphRetrieved(_u, mut glyph)) = mgr.read_result() { glyph.set_blink(true); glyph.set_reverse(true); if last_char { glyph.set_char(' '); } mgr.set_glyph( self.g_id, glyph, self.cursor_position.0, self.cursor_position.1, ); } } pub fn delete(&mut self, mgr: &mut Manager) { let next_position = (self.cursor_position.0 + 1, self.cursor_position.1); if next_position.0 > self.max_position.0 { return; } let len = self.text[self.cursor_position.1].chars().count(); match len.cmp(&(next_position.0 - 2)) { std::cmp::Ordering::Less => {} std::cmp::Ordering::Equal => { self.text[self.cursor_position.1].pop(); mgr.set_glyph( self.g_id, Glyph::plain(), self.cursor_position.0, self.cursor_position.1, ); } std::cmp::Ordering::Greater => { let mut chars = self.text[next_position.1].chars(); let mut new_string = String::with_capacity(len); for _i in 0..self.cursor_position.0 - 2 { if let Some(char) = chars.next() { new_string.push(char); } } let _skip = chars.next(); let mut i = next_position.0 - 1; for char in chars { new_string.push(char); mgr.set_glyph(self.g_id, Glyph::char(char), i, next_position.1); i += 1; } mgr.set_glyph(self.g_id, Glyph::plain(), i, next_position.1); self.text[self.cursor_position.1] = new_string; } } mgr.get_glyph(self.g_id, self.cursor_position.0, self.cursor_position.1); if let Ok(AnimOk::GlyphRetrieved(_u, mut glyph)) = mgr.read_result() { glyph.set_blink(true); glyph.set_reverse(true); mgr.set_glyph( self.g_id, glyph, self.cursor_position.0, self.cursor_position.1, ); } } pub fn remove_chars_from_cursor_to_end(&mut self, mgr: &mut Manager) { let mut chars = self.text[self.cursor_position.1].chars(); let mut new_string = String::with_capacity(self.max_position.0); for _i in 0..self.cursor_position.0 - 2 { if let Some(char) = chars.next() { new_string.push(char); } else { break; } } let mut glyph = Glyph::plain(); glyph.set_blink(true); glyph.set_reverse(true); mgr.set_glyph( self.g_id, glyph, self.cursor_position.0, self.cursor_position.1, ); let mut i = 1; while chars.next().is_some() { mgr.set_glyph( self.g_id, Glyph::plain(), self.cursor_position.0 + i, self.cursor_position.1, ); i += 1; } self.text[self.cursor_position.1] = new_string; } pub fn move_to_line_start(&mut self, mgr: &mut Manager) { mgr.get_glyph(self.g_id, self.cursor_position.0, self.cursor_position.1); if let Ok(AnimOk::GlyphRetrieved(_u, mut glyph)) = mgr.read_result() { glyph.set_blink(false); glyph.set_reverse(false); mgr.set_glyph( self.g_id, glyph, self.cursor_position.0, self.cursor_position.1, ); } self.cursor_position.0 = 2; mgr.get_glyph(self.g_id, self.cursor_position.0, self.cursor_position.1); if let Ok(AnimOk::GlyphRetrieved(_u, mut glyph)) = mgr.read_result() { glyph.set_blink(true); glyph.set_reverse(true); mgr.set_glyph( self.g_id, glyph, self.cursor_position.0, self.cursor_position.1, ); } } pub fn move_to_line_end(&mut self, mgr: &mut Manager) { mgr.get_glyph(self.g_id, self.cursor_position.0, self.cursor_position.1); if let Ok(AnimOk::GlyphRetrieved(_u, mut glyph)) = mgr.read_result() { glyph.set_blink(false); glyph.set_reverse(false); mgr.set_glyph( self.g_id, glyph, self.cursor_position.0, self.cursor_position.1, ); } self.cursor_position.0 = self.text[self.cursor_position.1].chars().count() + 2; mgr.get_glyph(self.g_id, self.cursor_position.0, self.cursor_position.1); if let Ok(AnimOk::GlyphRetrieved(_u, mut glyph)) = mgr.read_result() { glyph.set_blink(true); glyph.set_reverse(true); mgr.set_glyph( self.g_id, glyph, self.cursor_position.0, self.cursor_position.1, ); } } pub fn toggle_style(&self, style: Style, mgr: &mut Manager) { mgr.get_glyph(self.g_id, self.cursor_position.0, self.cursor_position.1); if let Ok(AnimOk::GlyphRetrieved(_u, mut glyph)) = mgr.read_result() { match style { Style::Bright => glyph.set_bright(!glyph.bright), Style::Transparent => glyph.set_transparent(!glyph.transparent), Style::Italic => glyph.set_italic(!glyph.italic), Style::Underline => glyph.set_underline(!glyph.underline), Style::Blink => glyph.set_blink(!glyph.blink), Style::Blinkfast => glyph.set_blinkfast(!glyph.blink_fast), Style::Reverse => glyph.set_reverse(!glyph.reverse), Style::Strike => glyph.set_strike(!glyph.strike), }; mgr.set_glyph( self.g_id, glyph, self.cursor_position.0, self.cursor_position.1, ); } } pub fn move_cursor(&mut self, direction: Direction, mgr: &mut Manager) { mgr.get_glyph(self.g_id, self.cursor_position.0, self.cursor_position.1); if let Ok(AnimOk::GlyphRetrieved(_u, mut glyph)) = mgr.read_result() { glyph.set_blink(false); glyph.set_reverse(false); mgr.set_glyph( self.g_id, glyph, self.cursor_position.0, self.cursor_position.1, ); } match direction { Direction::Up => { self.cursor_position.1 -= 1; if self.cursor_position.1 < 1 { self.cursor_position.1 = self.max_position.1; } } Direction::Down => { self.cursor_position.1 += 1; if self.cursor_position.1 > self.max_position.1 { self.cursor_position.1 = 1; } } Direction::Left => { self.cursor_position.0 -= 1; if self.cursor_position.0 < 2 { self.cursor_position.0 = self.max_position.0; } } Direction::Right => { self.cursor_position.0 += 1; if self.cursor_position.0 > self.max_position.0 { self.cursor_position.0 = 2; } } } mgr.get_glyph(self.g_id, self.cursor_position.0, self.cursor_position.1); if let Ok(AnimOk::GlyphRetrieved(_u, mut glyph)) = mgr.read_result() { glyph.set_blink(true); glyph.set_reverse(true); mgr.set_glyph( self.g_id, glyph, self.cursor_position.0, self.cursor_position.1, ); } } } pub enum Direction { Left, Right, Up, Down, } pub enum Style { Bright, Transparent, Italic, Underline, Blink, Blinkfast, Reverse, Strike, }