diff options
author | Griffin Smith <root@gws.fyi> | 2019-07-28T02·16-0400 |
---|---|---|
committer | Griffin Smith <root@gws.fyi> | 2019-07-28T02·16-0400 |
commit | f22bcad817ee354b355d29b6b289894e2d15cfaa (patch) | |
tree | 509aa3b88f834ffaccd6a90b61ae2c1e1567622d /src/display | |
parent | 68e8ad8a0e6a5ac38b34658f03807ade603a687c (diff) |
Add a generic text-prompt system
Add a generic text-prompt system to the Game, and use it to prompt the character for their name on startup. There's also a Promise type in util, which is used for the result of the prompt.
Diffstat (limited to 'src/display')
-rw-r--r-- | src/display/color.rs | 1 | ||||
-rw-r--r-- | src/display/viewport.rs | 97 |
2 files changed, 87 insertions, 11 deletions
diff --git a/src/display/color.rs b/src/display/color.rs index 7d024a960d97..2a023f1d9564 100644 --- a/src/display/color.rs +++ b/src/display/color.rs @@ -92,7 +92,6 @@ impl<'de> Visitor<'de> for ColorVisitor { Ok(Color(Box::new(color::LightYellow))) } "magenta" => Ok(Color(Box::new(color::Magenta))), - "magenta" => Ok(Color(Box::new(color::Magenta))), "red" => Ok(Color(Box::new(color::Red))), "white" => Ok(Color(Box::new(color::White))), "yellow" => Ok(Color(Box::new(color::Yellow))), diff --git a/src/display/viewport.rs b/src/display/viewport.rs index b510b0504c58..372c0a2969d5 100644 --- a/src/display/viewport.rs +++ b/src/display/viewport.rs @@ -2,10 +2,21 @@ use super::BoxStyle; use super::Draw; use crate::display::draw_box::draw_box; use crate::display::utils::clone_times; -use crate::types::{pos, BoundingBox, Position, Positioned}; +use crate::types::{pos, BoundingBox, Direction, Position, Positioned}; use std::fmt::{self, Debug}; use std::io::{self, Write}; +pub enum CursorState { + Game, + Prompt(Position), +} + +impl Default for CursorState { + fn default() -> Self { + CursorState::Game + } +} + pub struct Viewport<W> { /// The box describing the visible part of the viewport. /// @@ -24,9 +35,12 @@ pub struct Viewport<W> { /// The actual screen that the viewport writes to pub out: W, + cursor_state: CursorState, + /// Reset the cursor back to this position after every draw - pub cursor_position: Position, + pub game_cursor_position: Position, } + impl<W> Viewport<W> { pub fn new(outer: BoundingBox, inner: BoundingBox, out: W) -> Self { Viewport { @@ -34,7 +48,8 @@ impl<W> Viewport<W> { inner, out, game: outer.move_tr_corner(Position { x: 0, y: 1 }), - cursor_position: pos(0, 0), + cursor_state: Default::default(), + game_cursor_position: pos(0, 0), } } @@ -72,7 +87,7 @@ impl<W: Write> Viewport<W> { } fn reset_cursor(&mut self) -> io::Result<()> { - self.cursor_goto(self.cursor_position) + self.cursor_goto(self.game_cursor_position) } /// Move the cursor to the given inner-relative position @@ -97,23 +112,85 @@ impl<W: Write> Viewport<W> { /// Will overwrite any message already present, and if the given message is /// longer than the screen will truncate. This means callers should handle /// message buffering and ellipsisization - pub fn write_message(&mut self, msg: &str) -> io::Result<()> { + pub fn write_message(&mut self, msg: &str) -> io::Result<usize> { + let msg_to_write = if msg.len() <= self.outer.dimensions.w as usize { + msg + } else { + &msg[0..self.outer.dimensions.w as usize] + }; write!( self, "{}{}{}", self.outer.position.cursor_goto(), - if msg.len() <= self.outer.dimensions.w as usize { - msg - } else { - &msg[0..self.outer.dimensions.w as usize] - }, + msg_to_write, clone_times::<_, String>( " ".to_string(), self.outer.dimensions.w - msg.len() as u16 ), )?; + self.reset_cursor()?; + Ok(msg_to_write.len()) + } + + pub fn clear_message(&mut self) -> io::Result<()> { + write!( + self, + "{}{}", + self.outer.position.cursor_goto(), + clone_times::<_, String>( + " ".to_string(), + self.outer.dimensions.w as u16 + ) + )?; self.reset_cursor() } + + /// Write a prompt requesting text input to the message area on the screen. + /// + /// Will overwrite any message already present, and if the given message is + /// longer than the screen will truncate. This means callers should handle + /// message buffering and ellipsisization + pub fn write_prompt<'a, 'b>(&'a mut self, msg: &'b str) -> io::Result<()> { + let len = self.write_message(msg)? + 1; + let pos = self.outer.position + pos(len as i16, 0); + self.cursor_state = CursorState::Prompt(pos); + write!(self, "{}", pos.cursor_goto())?; + self.flush() + } + + pub fn push_prompt_chr(&mut self, chr: char) -> io::Result<()> { + match self.cursor_state { + CursorState::Prompt(pos) => { + write!(self, "{}", chr)?; + self.cursor_state = CursorState::Prompt(pos + Direction::Right); + } + _ => {} + } + Ok(()) + } + + pub fn pop_prompt_chr(&mut self) -> io::Result<()> { + match self.cursor_state { + CursorState::Prompt(pos) => { + let new_pos = pos + Direction::Left; + write!( + self, + "{} {}", + new_pos.cursor_goto(), + new_pos.cursor_goto() + )?; + self.cursor_state = CursorState::Prompt(new_pos); + } + _ => {} + } + Ok(()) + } + + pub fn clear_prompt(&mut self) -> io::Result<()> { + self.clear_message()?; + self.cursor_state = CursorState::Game; + Ok(()) + } } impl<W> Positioned for Viewport<W> { |