Improve game rules configuration screen
This commit is contained in:
		@@ -1,3 +1,6 @@
 | 
			
		||||
use std::time::Duration;
 | 
			
		||||
use tui::style::Color;
 | 
			
		||||
 | 
			
		||||
pub const TICK_RATE: Duration = Duration::from_millis(250);
 | 
			
		||||
 | 
			
		||||
pub const HIGHLIGHT_COLOR: Color = Color::Green;
 | 
			
		||||
 
 | 
			
		||||
@@ -14,13 +14,14 @@ use tui::Terminal;
 | 
			
		||||
 | 
			
		||||
use cli_player::server::start_server_if_missing;
 | 
			
		||||
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>> {
 | 
			
		||||
    // 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(
 | 
			
		||||
        ErrorKind::Other,
 | 
			
		||||
        format!("configured rules: {:?}", res),
 | 
			
		||||
        format!("result: {:?}", res),
 | 
			
		||||
    ))?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
extern crate num as num_renamed;
 | 
			
		||||
 | 
			
		||||
use std::cmp::max;
 | 
			
		||||
use std::io;
 | 
			
		||||
use std::time::{Duration, Instant};
 | 
			
		||||
 | 
			
		||||
@@ -64,7 +63,7 @@ pub fn configure_play_rules<B: Backend>(
 | 
			
		||||
 | 
			
		||||
                    // Navigate between fields
 | 
			
		||||
                    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
 | 
			
		||||
                    KeyCode::Enter => {
 | 
			
		||||
@@ -127,9 +126,11 @@ pub fn configure_play_rules<B: Backend>(
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Apply new cursor position
 | 
			
		||||
            cursor_pos = max(0, cursor_pos);
 | 
			
		||||
            if let Some(val) = num_renamed::FromPrimitive::from_u64(cursor_pos as u64) {
 | 
			
		||||
                model.curr_field = val;
 | 
			
		||||
            model.curr_field = if cursor_pos < 0 {
 | 
			
		||||
                EditingField::OK
 | 
			
		||||
            } else {
 | 
			
		||||
                num_renamed::FromPrimitive::from_u64(cursor_pos as u64)
 | 
			
		||||
                    .unwrap_or(EditingField::MapWidth)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if last_tick.elapsed() >= TICK_RATE {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,14 +4,14 @@ use std::time::{Duration, Instant};
 | 
			
		||||
use crossterm::event;
 | 
			
		||||
use crossterm::event::{Event, KeyCode};
 | 
			
		||||
use tui::backend::Backend;
 | 
			
		||||
use tui::style::{Color, Modifier, Style};
 | 
			
		||||
use tui::style::*;
 | 
			
		||||
use tui::text::*;
 | 
			
		||||
use tui::widgets::*;
 | 
			
		||||
use tui::{Frame, Terminal};
 | 
			
		||||
 | 
			
		||||
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::ScreenResult;
 | 
			
		||||
 | 
			
		||||
@@ -86,7 +86,7 @@ fn ui<B: Backend>(f: &mut Frame<B>, model: &mut SelectPlayModeScreen) {
 | 
			
		||||
        )
 | 
			
		||||
        .highlight_style(
 | 
			
		||||
            Style::default()
 | 
			
		||||
                .fg(Color::Green)
 | 
			
		||||
                .fg(HIGHLIGHT_COLOR)
 | 
			
		||||
                .add_modifier(Modifier::BOLD),
 | 
			
		||||
        )
 | 
			
		||||
        .highlight_symbol(">> ");
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,14 @@
 | 
			
		||||
use std::io;
 | 
			
		||||
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 crossterm::event;
 | 
			
		||||
use crossterm::event::{Event, KeyCode};
 | 
			
		||||
use tui::backend::Backend;
 | 
			
		||||
use tui::style::{Color, Modifier, Style};
 | 
			
		||||
use tui::style::*;
 | 
			
		||||
use tui::text::Text;
 | 
			
		||||
use tui::widgets::{Block, Borders, List, ListItem, ListState};
 | 
			
		||||
use tui::widgets::*;
 | 
			
		||||
use tui::{Frame, Terminal};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
 | 
			
		||||
@@ -95,7 +95,7 @@ fn ui<B: Backend>(f: &mut Frame<B>, model: &mut SelectPlayModeScreen) {
 | 
			
		||||
        )
 | 
			
		||||
        .highlight_style(
 | 
			
		||||
            Style::default()
 | 
			
		||||
                .fg(Color::Green)
 | 
			
		||||
                .fg(HIGHLIGHT_COLOR)
 | 
			
		||||
                .add_modifier(Modifier::BOLD),
 | 
			
		||||
        )
 | 
			
		||||
        .highlight_symbol(">> ");
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
use std::fmt::Display;
 | 
			
		||||
 | 
			
		||||
use crate::constants::HIGHLIGHT_COLOR;
 | 
			
		||||
use tui::buffer::Buffer;
 | 
			
		||||
use tui::layout::Rect;
 | 
			
		||||
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) {
 | 
			
		||||
            (true, _) => Style::default(),
 | 
			
		||||
            (_, 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);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,8 @@
 | 
			
		||||
use crate::constants::HIGHLIGHT_COLOR;
 | 
			
		||||
use std::fmt::Display;
 | 
			
		||||
use tui::buffer::Buffer;
 | 
			
		||||
use tui::layout::Rect;
 | 
			
		||||
use tui::style::{Color, Style};
 | 
			
		||||
use tui::style::*;
 | 
			
		||||
use tui::widgets::*;
 | 
			
		||||
 | 
			
		||||
pub struct CheckboxWidget {
 | 
			
		||||
@@ -48,7 +49,7 @@ impl Widget for CheckboxWidget {
 | 
			
		||||
 | 
			
		||||
        let input = Paragraph::new(paragraph.as_ref()).style(match &self.is_editing {
 | 
			
		||||
            false => Style::default(),
 | 
			
		||||
            true => Style::default().fg(Color::Yellow),
 | 
			
		||||
            true => Style::default().fg(HIGHLIGHT_COLOR),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        input.render(area, buf);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,9 @@
 | 
			
		||||
use std::fmt::Display;
 | 
			
		||||
 | 
			
		||||
use crate::constants::HIGHLIGHT_COLOR;
 | 
			
		||||
use tui::buffer::Buffer;
 | 
			
		||||
use tui::layout::Rect;
 | 
			
		||||
use tui::style::{Color, Style};
 | 
			
		||||
use tui::style::*;
 | 
			
		||||
use tui::text::*;
 | 
			
		||||
use tui::widgets::{Block, Borders, Paragraph, Widget};
 | 
			
		||||
 | 
			
		||||
@@ -37,20 +38,25 @@ impl Widget for TextEditorWidget {
 | 
			
		||||
            self.value.to_string(),
 | 
			
		||||
            match &self.input_mode {
 | 
			
		||||
                InputMode::Normal => Style::default(),
 | 
			
		||||
                InputMode::Editing => Style::default().fg(Color::Yellow),
 | 
			
		||||
                InputMode::Editing => Style::default().fg(HIGHLIGHT_COLOR),
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let mut spans = vec![span];
 | 
			
		||||
 | 
			
		||||
        // Add cursor if field is highlighted
 | 
			
		||||
        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 input = Paragraph::new(text).block(
 | 
			
		||||
            Block::default()
 | 
			
		||||
                .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()),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -91,18 +91,28 @@ impl GameRules {
 | 
			
		||||
 | 
			
		||||
        let mut errors = vec![];
 | 
			
		||||
 | 
			
		||||
        if self.map_width < config.min_map_width || self.map_width > config.max_map_width {
 | 
			
		||||
            errors.push("Map width is outside bounds!");
 | 
			
		||||
        if self.map_width < config.min_map_width {
 | 
			
		||||
            errors.push("Map width is too small!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if self.map_height < config.min_map_height || self.map_height > config.max_map_height {
 | 
			
		||||
            errors.push("Map height is outside bounds!");
 | 
			
		||||
        if self.map_width > config.max_map_width {
 | 
			
		||||
            errors.push("Map width is too big!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if self.boats_list().len() < config.min_boats_number
 | 
			
		||||
            || self.boats_list().len() > config.max_boats_number
 | 
			
		||||
        {
 | 
			
		||||
            errors.push("The number of boats is invalid!");
 | 
			
		||||
        if self.map_height < config.min_map_height {
 | 
			
		||||
            errors.push("Map height is too small!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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() {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user