pub enum CursorMove { Up(usize), Down(usize), Left(usize), Right(usize), Top, Bottom, Begin, End, Jump((usize, usize)), Relative((isize, isize)), } #[derive(Default, Debug, Clone)] pub struct Cursor { x: isize, y: isize, x_max: isize, y_max: isize, } impl Cursor { pub const fn new() -> Self { Self { x: 0, y: 0, x_max: 0, y_max: 0, } } pub const fn with_position(mut self, x: isize, y: isize) -> Self { self.x = x; self.y = y; self } pub const fn with_max(mut self, x: isize, y: isize) -> Self { self.x_max = x; self.y_max = y; self } pub fn x(&self) -> usize { self.x as usize } pub fn y(&self) -> usize { self.y as usize } pub fn set_x_max(&mut self, max: usize) { self.x_max = max as isize; } pub fn set_y_max(&mut self, max: usize) { self.y_max = max as isize; } pub fn move_checked(&mut self, m: CursorMove) { self.move_unchecked(m); self.correct_cursor_position(); } pub fn move_unchecked(&mut self, m: CursorMove) { match m { CursorMove::Up(n) => self.y -= n as isize, CursorMove::Down(n) => self.y += n as isize, CursorMove::Left(n) => self.x -= n as isize, CursorMove::Right(n) => self.x += n as isize, CursorMove::Top => self.y = 0, CursorMove::Bottom => self.y = self.y_max, CursorMove::Begin => self.x = 0, CursorMove::End => self.x = self.x_max, CursorMove::Jump((x, y)) => { self.x = x as isize; self.y = y as isize; }, CursorMove::Relative((x, y)) => { self.x += x; self.y += y; } }; } pub fn correct_cursor_position(&mut self) { self.y = self.y.max(0).min(self.y_max); self.x = self.x.max(0).min(self.x_max); } pub fn is_at_start(&self) -> bool { self.x == 0 } pub fn is_at_end(&self) -> bool { self.x == self.x_max } pub fn is_at_top(&self) -> bool { self.y == 0 } pub fn is_at_bottom(&self) -> bool { self.y == self.y_max } }