Improve game rules configuration screen

This commit is contained in:
Pierre HUBERT 2022-10-02 19:17:29 +02:00
parent c9f643e224
commit 17a4edf417
9 changed files with 51 additions and 28 deletions

View File

@ -1,3 +1,6 @@
use std::time::Duration; use std::time::Duration;
use tui::style::Color;
pub const TICK_RATE: Duration = Duration::from_millis(250); pub const TICK_RATE: Duration = Duration::from_millis(250);
pub const HIGHLIGHT_COLOR: Color = Color::Green;

View File

@ -14,13 +14,14 @@ use tui::Terminal;
use cli_player::server::start_server_if_missing; use cli_player::server::start_server_if_missing;
use cli_player::ui_screens::*; use cli_player::ui_screens::*;
use sea_battle_backend::data::GameRules;
async fn run_app<B: Backend>(terminal: &mut Terminal<B>) -> Result<(), Box<dyn Error>> { async fn run_app<B: Backend>(terminal: &mut Terminal<B>) -> Result<(), Box<dyn Error>> {
// Temporary code // Temporary code
let res = select_bot_type::select_bot_type(terminal)?; let res = configure_game_rules::configure_play_rules(GameRules::default(), terminal)?; // select_bot_type::select_bot_type(terminal)?;
Err(io::Error::new( Err(io::Error::new(
ErrorKind::Other, ErrorKind::Other,
format!("configured rules: {:?}", res), format!("result: {:?}", res),
))?; ))?;
Ok(()) Ok(())
} }

View File

@ -1,6 +1,5 @@
extern crate num as num_renamed; extern crate num as num_renamed;
use std::cmp::max;
use std::io; use std::io;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@ -64,7 +63,7 @@ pub fn configure_play_rules<B: Backend>(
// Navigate between fields // Navigate between fields
KeyCode::Up | KeyCode::Left => cursor_pos -= 1, KeyCode::Up | KeyCode::Left => cursor_pos -= 1,
KeyCode::Down | KeyCode::Right => cursor_pos += 1, KeyCode::Down | KeyCode::Right | KeyCode::Tab => cursor_pos += 1,
// Submit results // Submit results
KeyCode::Enter => { KeyCode::Enter => {
@ -127,9 +126,11 @@ pub fn configure_play_rules<B: Backend>(
} }
// Apply new cursor position // Apply new cursor position
cursor_pos = max(0, cursor_pos); model.curr_field = if cursor_pos < 0 {
if let Some(val) = num_renamed::FromPrimitive::from_u64(cursor_pos as u64) { EditingField::OK
model.curr_field = val; } else {
num_renamed::FromPrimitive::from_u64(cursor_pos as u64)
.unwrap_or(EditingField::MapWidth)
} }
} }
if last_tick.elapsed() >= TICK_RATE { if last_tick.elapsed() >= TICK_RATE {

View File

@ -4,14 +4,14 @@ use std::time::{Duration, Instant};
use crossterm::event; use crossterm::event;
use crossterm::event::{Event, KeyCode}; use crossterm::event::{Event, KeyCode};
use tui::backend::Backend; use tui::backend::Backend;
use tui::style::{Color, Modifier, Style}; use tui::style::*;
use tui::text::*; use tui::text::*;
use tui::widgets::*; use tui::widgets::*;
use tui::{Frame, Terminal}; use tui::{Frame, Terminal};
use sea_battle_backend::data::{BotDescription, BotType, PlayConfiguration}; use sea_battle_backend::data::{BotDescription, BotType, PlayConfiguration};
use crate::constants::TICK_RATE; use crate::constants::{HIGHLIGHT_COLOR, TICK_RATE};
use crate::ui_screens::utils::centered_rect_size; use crate::ui_screens::utils::centered_rect_size;
use crate::ui_screens::ScreenResult; use crate::ui_screens::ScreenResult;
@ -86,7 +86,7 @@ fn ui<B: Backend>(f: &mut Frame<B>, model: &mut SelectPlayModeScreen) {
) )
.highlight_style( .highlight_style(
Style::default() Style::default()
.fg(Color::Green) .fg(HIGHLIGHT_COLOR)
.add_modifier(Modifier::BOLD), .add_modifier(Modifier::BOLD),
) )
.highlight_symbol(">> "); .highlight_symbol(">> ");

View File

@ -1,14 +1,14 @@
use std::io; use std::io;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use crate::constants::TICK_RATE; use crate::constants::{HIGHLIGHT_COLOR, TICK_RATE};
use crate::ui_screens::utils::centered_rect_size; use crate::ui_screens::utils::centered_rect_size;
use crossterm::event; use crossterm::event;
use crossterm::event::{Event, KeyCode}; use crossterm::event::{Event, KeyCode};
use tui::backend::Backend; use tui::backend::Backend;
use tui::style::{Color, Modifier, Style}; use tui::style::*;
use tui::text::Text; use tui::text::Text;
use tui::widgets::{Block, Borders, List, ListItem, ListState}; use tui::widgets::*;
use tui::{Frame, Terminal}; use tui::{Frame, Terminal};
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)] #[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
@ -95,7 +95,7 @@ fn ui<B: Backend>(f: &mut Frame<B>, model: &mut SelectPlayModeScreen) {
) )
.highlight_style( .highlight_style(
Style::default() Style::default()
.fg(Color::Green) .fg(HIGHLIGHT_COLOR)
.add_modifier(Modifier::BOLD), .add_modifier(Modifier::BOLD),
) )
.highlight_symbol(">> "); .highlight_symbol(">> ");

View File

@ -1,5 +1,6 @@
use std::fmt::Display; use std::fmt::Display;
use crate::constants::HIGHLIGHT_COLOR;
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};
@ -37,7 +38,7 @@ impl Widget for ButtonWidget {
let input = Paragraph::new(label.as_ref()).style(match (self.disabled, self.is_hovered) { let input = Paragraph::new(label.as_ref()).style(match (self.disabled, self.is_hovered) {
(true, _) => Style::default(), (true, _) => Style::default(),
(_, false) => Style::default().bg(Color::DarkGray), (_, false) => Style::default().bg(Color::DarkGray),
(_, true) => Style::default().fg(Color::White).bg(Color::Yellow), (_, true) => Style::default().fg(Color::White).bg(HIGHLIGHT_COLOR),
}); });
input.render(area, buf); input.render(area, buf);

View File

@ -1,7 +1,8 @@
use crate::constants::HIGHLIGHT_COLOR;
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::*;
use tui::widgets::*; use tui::widgets::*;
pub struct CheckboxWidget { pub struct CheckboxWidget {
@ -48,7 +49,7 @@ impl Widget for CheckboxWidget {
let input = Paragraph::new(paragraph.as_ref()).style(match &self.is_editing { let input = Paragraph::new(paragraph.as_ref()).style(match &self.is_editing {
false => Style::default(), false => Style::default(),
true => Style::default().fg(Color::Yellow), true => Style::default().fg(HIGHLIGHT_COLOR),
}); });
input.render(area, buf); input.render(area, buf);

View File

@ -1,8 +1,9 @@
use std::fmt::Display; use std::fmt::Display;
use crate::constants::HIGHLIGHT_COLOR;
use tui::buffer::Buffer; use tui::buffer::Buffer;
use tui::layout::Rect; use tui::layout::Rect;
use tui::style::{Color, Style}; use tui::style::*;
use tui::text::*; use tui::text::*;
use tui::widgets::{Block, Borders, Paragraph, Widget}; use tui::widgets::{Block, Borders, Paragraph, Widget};
@ -37,20 +38,25 @@ impl Widget for TextEditorWidget {
self.value.to_string(), self.value.to_string(),
match &self.input_mode { match &self.input_mode {
InputMode::Normal => Style::default(), InputMode::Normal => Style::default(),
InputMode::Editing => Style::default().fg(Color::Yellow), InputMode::Editing => Style::default().fg(HIGHLIGHT_COLOR),
}, },
); );
let mut spans = vec![span]; let mut spans = vec![span];
// Add cursor if field is highlighted
if self.input_mode == InputMode::Editing { if self.input_mode == InputMode::Editing {
spans.push(Span::styled(" ", Style::default().bg(Color::Yellow))) spans.push(Span::styled(" ", Style::default().bg(HIGHLIGHT_COLOR)))
} }
let text = Text::from(Spans::from(spans)); let text = Text::from(Spans::from(spans));
let input = Paragraph::new(text).block( let input = Paragraph::new(text).block(
Block::default() Block::default()
.borders(Borders::ALL) .borders(Borders::ALL)
.border_style(match self.input_mode {
InputMode::Normal => Style::default(),
InputMode::Editing => Style::default().fg(HIGHLIGHT_COLOR),
})
.title(self.label.as_ref()), .title(self.label.as_ref()),
); );

View File

@ -91,18 +91,28 @@ impl GameRules {
let mut errors = vec![]; let mut errors = vec![];
if self.map_width < config.min_map_width || self.map_width > config.max_map_width { if self.map_width < config.min_map_width {
errors.push("Map width is outside bounds!"); errors.push("Map width is too small!");
} }
if self.map_height < config.min_map_height || self.map_height > config.max_map_height { if self.map_width > config.max_map_width {
errors.push("Map height is outside bounds!"); errors.push("Map width is too big!");
} }
if self.boats_list().len() < config.min_boats_number if self.map_height < config.min_map_height {
|| self.boats_list().len() > config.max_boats_number errors.push("Map height is too small!");
{ }
errors.push("The number of boats is invalid!");
if self.map_height > config.max_map_height {
errors.push("Map height is too big!");
}
if self.boats_list().len() < config.min_boats_number {
errors.push("There is not enough boats!");
}
if self.boats_list().len() > config.max_boats_number {
errors.push("There are too many boats!");
} }
for boat in self.boats_list() { for boat in self.boats_list() {