Configuration fields in game rules screen are editable
This commit is contained in:
		@@ -1,5 +1,6 @@
 | 
				
			|||||||
use std::error::Error;
 | 
					use std::error::Error;
 | 
				
			||||||
use std::io;
 | 
					use std::io;
 | 
				
			||||||
 | 
					use std::io::ErrorKind;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crossterm::event::DisableMouseCapture;
 | 
					use crossterm::event::DisableMouseCapture;
 | 
				
			||||||
use crossterm::event::EnableMouseCapture;
 | 
					use crossterm::event::EnableMouseCapture;
 | 
				
			||||||
@@ -22,7 +23,10 @@ async fn run_app<B: Backend>(terminal: &mut Terminal<B>) -> Result<(), Box<dyn E
 | 
				
			|||||||
        PlayConfiguration::default(),
 | 
					        PlayConfiguration::default(),
 | 
				
			||||||
        terminal,
 | 
					        terminal,
 | 
				
			||||||
    )?;
 | 
					    )?;
 | 
				
			||||||
    println!("configured rules: {:?}", res);
 | 
					    Err(std::io::Error::new(
 | 
				
			||||||
 | 
					        ErrorKind::Other,
 | 
				
			||||||
 | 
					        format!("configured rules: {:?}", res),
 | 
				
			||||||
 | 
					    ))?;
 | 
				
			||||||
    Ok(())
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,8 +8,6 @@ use crossterm::event;
 | 
				
			|||||||
use crossterm::event::{Event, KeyCode};
 | 
					use crossterm::event::{Event, KeyCode};
 | 
				
			||||||
use tui::backend::Backend;
 | 
					use tui::backend::Backend;
 | 
				
			||||||
use tui::layout::{Constraint, Direction, Layout, Margin};
 | 
					use tui::layout::{Constraint, Direction, Layout, Margin};
 | 
				
			||||||
use tui::style::*;
 | 
					 | 
				
			||||||
use tui::text::Text;
 | 
					 | 
				
			||||||
use tui::widgets::*;
 | 
					use tui::widgets::*;
 | 
				
			||||||
use tui::{Frame, Terminal};
 | 
					use tui::{Frame, Terminal};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -68,9 +66,69 @@ pub fn configure_play_rules<B: Backend>(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if let Event::Key(key) = event::read()? {
 | 
					            if let Event::Key(key) = event::read()? {
 | 
				
			||||||
                match key.code {
 | 
					                match key.code {
 | 
				
			||||||
 | 
					                    // Quit app
 | 
				
			||||||
                    KeyCode::Char('q') => return Ok(ConfigureGameRulesResult::Canceled),
 | 
					                    KeyCode::Char('q') => return Ok(ConfigureGameRulesResult::Canceled),
 | 
				
			||||||
                    KeyCode::Up => cursor_pos -= 1,
 | 
					
 | 
				
			||||||
                    KeyCode::Down => cursor_pos += 1,
 | 
					                    // Navigate between fields
 | 
				
			||||||
 | 
					                    KeyCode::Up | KeyCode::Left => cursor_pos -= 1,
 | 
				
			||||||
 | 
					                    KeyCode::Down | KeyCode::Right => cursor_pos += 1,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // Submit results
 | 
				
			||||||
 | 
					                    KeyCode::Enter => {
 | 
				
			||||||
 | 
					                        if model.curr_field == EditingField::Cancel {
 | 
				
			||||||
 | 
					                            return Ok(ConfigureGameRulesResult::Canceled);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if model.curr_field == EditingField::OK && model.rules.is_valid() {
 | 
				
			||||||
 | 
					                            return Ok(ConfigureGameRulesResult::Ok(model.rules));
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    KeyCode::Char(' ') => {
 | 
				
			||||||
 | 
					                        if model.curr_field == EditingField::BoatsCanTouch {
 | 
				
			||||||
 | 
					                            model.rules.boats_can_touch = !model.rules.boats_can_touch;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if model.curr_field == EditingField::PlayerContinueOnHit {
 | 
				
			||||||
 | 
					                            model.rules.player_continue_on_hit =
 | 
				
			||||||
 | 
					                                !model.rules.player_continue_on_hit;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    KeyCode::Backspace => {
 | 
				
			||||||
 | 
					                        if model.curr_field == EditingField::MapWidth {
 | 
				
			||||||
 | 
					                            model.rules.map_width /= 10;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if model.curr_field == EditingField::MapHeight {
 | 
				
			||||||
 | 
					                            model.rules.map_height /= 10;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if model.curr_field == EditingField::BoatsList
 | 
				
			||||||
 | 
					                            && !model.rules.boats_list().is_empty()
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            model.rules.remove_last_boat();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    KeyCode::Char(c) if ('0'..='9').contains(&c) => {
 | 
				
			||||||
 | 
					                        let val = c.to_string().parse::<usize>().unwrap_or_default();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if model.curr_field == EditingField::MapWidth {
 | 
				
			||||||
 | 
					                            model.rules.map_width *= 10;
 | 
				
			||||||
 | 
					                            model.rules.map_width += val;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if model.curr_field == EditingField::MapHeight {
 | 
				
			||||||
 | 
					                            model.rules.map_height *= 10;
 | 
				
			||||||
 | 
					                            model.rules.map_height += val;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if model.curr_field == EditingField::BoatsList {
 | 
				
			||||||
 | 
					                            model.rules.add_boat(val);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    _ => {}
 | 
					                    _ => {}
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,12 @@
 | 
				
			|||||||
use std::fmt::Display;
 | 
					use std::fmt::Display;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use tui::buffer::Buffer;
 | 
					use tui::buffer::Buffer;
 | 
				
			||||||
use tui::layout::Rect;
 | 
					use tui::layout::Rect;
 | 
				
			||||||
use tui::style::{Color, Style};
 | 
					use tui::style::{Color, Style};
 | 
				
			||||||
 | 
					use tui::text::*;
 | 
				
			||||||
use tui::widgets::{Block, Borders, Paragraph, Widget};
 | 
					use tui::widgets::{Block, Borders, Paragraph, Widget};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Eq, PartialEq)]
 | 
				
			||||||
pub enum InputMode {
 | 
					pub enum InputMode {
 | 
				
			||||||
    Normal,
 | 
					    Normal,
 | 
				
			||||||
    Editing,
 | 
					    Editing,
 | 
				
			||||||
@@ -30,12 +33,22 @@ impl TextEditorWidget {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
impl Widget for TextEditorWidget {
 | 
					impl Widget for TextEditorWidget {
 | 
				
			||||||
    fn render(self, area: Rect, buf: &mut Buffer) {
 | 
					    fn render(self, area: Rect, buf: &mut Buffer) {
 | 
				
			||||||
        let input = Paragraph::new(self.value.as_ref())
 | 
					        let span = Span::styled(
 | 
				
			||||||
            .style(match &self.input_mode {
 | 
					            self.value.to_string(),
 | 
				
			||||||
 | 
					            match &self.input_mode {
 | 
				
			||||||
                InputMode::Normal => Style::default(),
 | 
					                InputMode::Normal => Style::default(),
 | 
				
			||||||
                InputMode::Editing => Style::default().fg(Color::Yellow),
 | 
					                InputMode::Editing => Style::default().fg(Color::Yellow),
 | 
				
			||||||
            })
 | 
					            },
 | 
				
			||||||
            .block(
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut spans = vec![span];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.input_mode == InputMode::Editing {
 | 
				
			||||||
 | 
					            spans.push(Span::styled(" ", Style::default().bg(Color::Yellow)))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let text = Text::from(Spans::from(spans));
 | 
				
			||||||
 | 
					        let input = Paragraph::new(text).block(
 | 
				
			||||||
            Block::default()
 | 
					            Block::default()
 | 
				
			||||||
                .borders(Borders::ALL)
 | 
					                .borders(Borders::ALL)
 | 
				
			||||||
                .title(self.label.as_ref()),
 | 
					                .title(self.label.as_ref()),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,6 +61,10 @@ impl GameRules {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// Get the list of boats for this configuration
 | 
					    /// Get the list of boats for this configuration
 | 
				
			||||||
    pub fn boats_list(&self) -> Vec<usize> {
 | 
					    pub fn boats_list(&self) -> Vec<usize> {
 | 
				
			||||||
 | 
					        if self.boats_str.is_empty() {
 | 
				
			||||||
 | 
					            return vec![];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.boats_str
 | 
					        self.boats_str
 | 
				
			||||||
            .split(',')
 | 
					            .split(',')
 | 
				
			||||||
            .map(|s| s.parse::<usize>().unwrap_or_default())
 | 
					            .map(|s| s.parse::<usize>().unwrap_or_default())
 | 
				
			||||||
@@ -78,7 +82,7 @@ impl GameRules {
 | 
				
			|||||||
    pub fn add_boat(&mut self, len: usize) {
 | 
					    pub fn add_boat(&mut self, len: usize) {
 | 
				
			||||||
        let mut list = self.boats_list();
 | 
					        let mut list = self.boats_list();
 | 
				
			||||||
        list.push(len);
 | 
					        list.push(len);
 | 
				
			||||||
        self.set_boats_list(&list[0..list.len() - 1]);
 | 
					        self.set_boats_list(&list);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Check game rules errors
 | 
					    /// Check game rules errors
 | 
				
			||||||
@@ -109,6 +113,11 @@ impl GameRules {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        errors
 | 
					        errors
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Check out whether these game rules are valid or not
 | 
				
			||||||
 | 
					    pub fn is_valid(&self) -> bool {
 | 
				
			||||||
 | 
					        return self.get_errors().is_empty();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user