Start to build edit game rules screen
This commit is contained in:
		
							
								
								
									
										71
									
								
								rust/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										71
									
								
								rust/Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -467,6 +467,9 @@ dependencies = [
 | 
			
		||||
 "env_logger",
 | 
			
		||||
 "lazy_static",
 | 
			
		||||
 "log",
 | 
			
		||||
 "num",
 | 
			
		||||
 "num-derive",
 | 
			
		||||
 "num-traits",
 | 
			
		||||
 "sea_battle_backend",
 | 
			
		||||
 "tokio",
 | 
			
		||||
 "tui",
 | 
			
		||||
@@ -1009,6 +1012,51 @@ dependencies = [
 | 
			
		||||
 "windows-sys",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "num"
 | 
			
		||||
version = "0.4.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "num-bigint",
 | 
			
		||||
 "num-complex",
 | 
			
		||||
 "num-integer",
 | 
			
		||||
 "num-iter",
 | 
			
		||||
 "num-rational",
 | 
			
		||||
 "num-traits",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "num-bigint"
 | 
			
		||||
version = "0.4.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "autocfg",
 | 
			
		||||
 "num-integer",
 | 
			
		||||
 "num-traits",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "num-complex"
 | 
			
		||||
version = "0.4.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "num-traits",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "num-derive"
 | 
			
		||||
version = "0.3.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "num-integer"
 | 
			
		||||
version = "0.1.45"
 | 
			
		||||
@@ -1019,6 +1067,29 @@ dependencies = [
 | 
			
		||||
 "num-traits",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "num-iter"
 | 
			
		||||
version = "0.1.43"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "autocfg",
 | 
			
		||||
 "num-integer",
 | 
			
		||||
 "num-traits",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "num-rational"
 | 
			
		||||
version = "0.4.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "autocfg",
 | 
			
		||||
 "num-bigint",
 | 
			
		||||
 "num-integer",
 | 
			
		||||
 "num-traits",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "num-traits"
 | 
			
		||||
version = "0.2.15"
 | 
			
		||||
 
 | 
			
		||||
@@ -13,4 +13,7 @@ env_logger = "0.9.0"
 | 
			
		||||
tui = "0.19.0"
 | 
			
		||||
crossterm = "0.25.0"
 | 
			
		||||
lazy_static = "1.4.0"
 | 
			
		||||
tokio = "1.21.2"
 | 
			
		||||
tokio = "1.21.2"
 | 
			
		||||
num = "0.4.0"
 | 
			
		||||
num-traits = "0.2.15"
 | 
			
		||||
num-derive = "0.3.3"
 | 
			
		||||
@@ -2,3 +2,4 @@ pub mod cli_args;
 | 
			
		||||
pub mod constants;
 | 
			
		||||
pub mod server;
 | 
			
		||||
pub mod ui_screens;
 | 
			
		||||
pub mod ui_widgets;
 | 
			
		||||
 
 | 
			
		||||
@@ -12,11 +12,17 @@ use tui::backend::{Backend, CrosstermBackend};
 | 
			
		||||
use tui::Terminal;
 | 
			
		||||
 | 
			
		||||
use cli_player::server::start_server_if_missing;
 | 
			
		||||
use cli_player::ui_screens::select_play_mode;
 | 
			
		||||
use cli_player::ui_screens::*;
 | 
			
		||||
use sea_battle_backend::data::{GameRules, PlayConfiguration};
 | 
			
		||||
 | 
			
		||||
async fn run_app<B: Backend>(terminal: &mut Terminal<B>) -> Result<(), Box<dyn Error>> {
 | 
			
		||||
    let res = select_play_mode::select_play_mode(terminal)?;
 | 
			
		||||
    println!("selected play mode: {:?}", res);
 | 
			
		||||
    // Temporary code
 | 
			
		||||
    let res = configure_game_rules::configure_play_rules(
 | 
			
		||||
        GameRules::default(),
 | 
			
		||||
        PlayConfiguration::default(),
 | 
			
		||||
        terminal,
 | 
			
		||||
    )?;
 | 
			
		||||
    println!("configured rules: {:?}", res);
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										162
									
								
								rust/cli_player/src/ui_screens/configure_game_rules.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								rust/cli_player/src/ui_screens/configure_game_rules.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,162 @@
 | 
			
		||||
extern crate num as num_renamed;
 | 
			
		||||
 | 
			
		||||
use std::cmp::max;
 | 
			
		||||
use std::io;
 | 
			
		||||
use std::time::{Duration, Instant};
 | 
			
		||||
 | 
			
		||||
use crossterm::event;
 | 
			
		||||
use crossterm::event::{Event, KeyCode};
 | 
			
		||||
use tui::backend::Backend;
 | 
			
		||||
use tui::layout::{Constraint, Direction, Layout, Margin};
 | 
			
		||||
use tui::style::*;
 | 
			
		||||
use tui::text::Text;
 | 
			
		||||
use tui::widgets::*;
 | 
			
		||||
use tui::{Frame, Terminal};
 | 
			
		||||
 | 
			
		||||
use sea_battle_backend::data::{GameRules, PlayConfiguration};
 | 
			
		||||
 | 
			
		||||
use crate::constants::TICK_RATE;
 | 
			
		||||
use crate::ui_screens::utils::centered_rect_size;
 | 
			
		||||
use crate::ui_widgets::button_widget::ButtonWidget;
 | 
			
		||||
use crate::ui_widgets::checkbox_widget::CheckboxWidget;
 | 
			
		||||
use crate::ui_widgets::text_editor_widget::TextEditorWidget;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum ConfigureGameRulesResult {
 | 
			
		||||
    Ok(GameRules),
 | 
			
		||||
    Canceled,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Eq, PartialEq)]
 | 
			
		||||
enum EditingField {
 | 
			
		||||
    MapWidth = 0,
 | 
			
		||||
    MapHeight,
 | 
			
		||||
    BoatsList,
 | 
			
		||||
    BoatsCanTouch,
 | 
			
		||||
    PlayerContinueOnHit,
 | 
			
		||||
    Cancel,
 | 
			
		||||
    OK,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct GameRulesConfigurationScreen {
 | 
			
		||||
    config: PlayConfiguration,
 | 
			
		||||
    rules: GameRules,
 | 
			
		||||
    curr_field: EditingField,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn configure_play_rules<B: Backend>(
 | 
			
		||||
    rules: GameRules,
 | 
			
		||||
    config: PlayConfiguration,
 | 
			
		||||
    terminal: &mut Terminal<B>,
 | 
			
		||||
) -> io::Result<ConfigureGameRulesResult> {
 | 
			
		||||
    let mut model = GameRulesConfigurationScreen {
 | 
			
		||||
        config,
 | 
			
		||||
        rules,
 | 
			
		||||
        curr_field: EditingField::OK,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let mut last_tick = Instant::now();
 | 
			
		||||
    loop {
 | 
			
		||||
        terminal.draw(|f| ui(f, &mut model))?;
 | 
			
		||||
 | 
			
		||||
        let timeout = TICK_RATE
 | 
			
		||||
            .checked_sub(last_tick.elapsed())
 | 
			
		||||
            .unwrap_or_else(|| Duration::from_secs(0));
 | 
			
		||||
 | 
			
		||||
        if crossterm::event::poll(timeout)? {
 | 
			
		||||
            let mut cursor_pos = model.curr_field as i32;
 | 
			
		||||
 | 
			
		||||
            if let Event::Key(key) = event::read()? {
 | 
			
		||||
                match key.code {
 | 
			
		||||
                    KeyCode::Char('q') => return Ok(ConfigureGameRulesResult::Canceled),
 | 
			
		||||
                    KeyCode::Up => cursor_pos -= 1,
 | 
			
		||||
                    KeyCode::Down => cursor_pos += 1,
 | 
			
		||||
                    _ => {}
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // 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;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if last_tick.elapsed() >= TICK_RATE {
 | 
			
		||||
            last_tick = Instant::now();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn ui<B: Backend>(f: &mut Frame<B>, model: &mut GameRulesConfigurationScreen) {
 | 
			
		||||
    let area = centered_rect_size(50, 16, f.size());
 | 
			
		||||
 | 
			
		||||
    let block = Block::default().title("Game rules").borders(Borders::ALL);
 | 
			
		||||
    f.render_widget(block, area);
 | 
			
		||||
 | 
			
		||||
    let chunks = Layout::default()
 | 
			
		||||
        .direction(Direction::Vertical)
 | 
			
		||||
        .constraints([
 | 
			
		||||
            Constraint::Length(3),
 | 
			
		||||
            Constraint::Length(3),
 | 
			
		||||
            Constraint::Length(3),
 | 
			
		||||
            Constraint::Length(1),
 | 
			
		||||
            Constraint::Length(1),
 | 
			
		||||
            Constraint::Length(3),
 | 
			
		||||
        ])
 | 
			
		||||
        .split(area.inner(&Margin {
 | 
			
		||||
            horizontal: 2,
 | 
			
		||||
            vertical: 1,
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
    let editor = TextEditorWidget::new(
 | 
			
		||||
        "Map width",
 | 
			
		||||
        &model.rules.map_width.to_string(),
 | 
			
		||||
        model.curr_field == EditingField::MapWidth,
 | 
			
		||||
    );
 | 
			
		||||
    f.render_widget(editor, chunks[EditingField::MapWidth as usize]);
 | 
			
		||||
 | 
			
		||||
    let editor = TextEditorWidget::new(
 | 
			
		||||
        "Map height",
 | 
			
		||||
        &model.rules.map_height.to_string(),
 | 
			
		||||
        model.curr_field == EditingField::MapHeight,
 | 
			
		||||
    );
 | 
			
		||||
    f.render_widget(editor, chunks[EditingField::MapHeight as usize]);
 | 
			
		||||
 | 
			
		||||
    let editor = TextEditorWidget::new(
 | 
			
		||||
        "Boats list",
 | 
			
		||||
        &model
 | 
			
		||||
            .rules
 | 
			
		||||
            .boats_list()
 | 
			
		||||
            .iter()
 | 
			
		||||
            .map(usize::to_string)
 | 
			
		||||
            .collect::<Vec<_>>()
 | 
			
		||||
            .join("; "),
 | 
			
		||||
        model.curr_field == EditingField::BoatsList,
 | 
			
		||||
    );
 | 
			
		||||
    f.render_widget(editor, chunks[EditingField::BoatsList as usize]);
 | 
			
		||||
 | 
			
		||||
    let editor = CheckboxWidget::new(
 | 
			
		||||
        "Boats can touch",
 | 
			
		||||
        model.rules.boats_can_touch,
 | 
			
		||||
        model.curr_field == EditingField::BoatsCanTouch,
 | 
			
		||||
    );
 | 
			
		||||
    f.render_widget(editor, chunks[EditingField::BoatsCanTouch as usize]);
 | 
			
		||||
 | 
			
		||||
    let editor = CheckboxWidget::new(
 | 
			
		||||
        "Player continue on hit",
 | 
			
		||||
        model.rules.player_continue_on_hit,
 | 
			
		||||
        model.curr_field == EditingField::PlayerContinueOnHit,
 | 
			
		||||
    );
 | 
			
		||||
    f.render_widget(editor, chunks[EditingField::PlayerContinueOnHit as usize]);
 | 
			
		||||
 | 
			
		||||
    let buttons_chunk = Layout::default()
 | 
			
		||||
        .direction(Direction::Horizontal)
 | 
			
		||||
        .constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
 | 
			
		||||
        .split(*chunks.last().unwrap());
 | 
			
		||||
 | 
			
		||||
    let button = ButtonWidget::new("Cancel", model.curr_field == EditingField::Cancel);
 | 
			
		||||
    f.render_widget(button, buttons_chunk[0]);
 | 
			
		||||
 | 
			
		||||
    let button = ButtonWidget::new("OK", model.curr_field == EditingField::OK);
 | 
			
		||||
    f.render_widget(button, buttons_chunk[1]);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,2 +1,3 @@
 | 
			
		||||
pub mod configure_game_rules;
 | 
			
		||||
pub mod select_play_mode;
 | 
			
		||||
pub mod utils;
 | 
			
		||||
 
 | 
			
		||||
@@ -31,16 +31,16 @@ pub fn centered_rect_percentage(percent_x: u16, percent_y: u16, r: Rect) -> Rect
 | 
			
		||||
pub fn centered_rect_size(width: u16, height: u16, parent: Rect) -> Rect {
 | 
			
		||||
    if parent.width < width || parent.height < height {
 | 
			
		||||
        return Rect {
 | 
			
		||||
            x: 0,
 | 
			
		||||
            y: 0,
 | 
			
		||||
            x: parent.x,
 | 
			
		||||
            y: parent.y,
 | 
			
		||||
            width: parent.width,
 | 
			
		||||
            height: parent.height,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Rect {
 | 
			
		||||
        x: (parent.width - width) / 2,
 | 
			
		||||
        y: (parent.height - height) / 2,
 | 
			
		||||
        x: parent.x + (parent.width - width) / 2,
 | 
			
		||||
        y: parent.y + (parent.height - height) / 2,
 | 
			
		||||
        width,
 | 
			
		||||
        height,
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										35
									
								
								rust/cli_player/src/ui_widgets/button_widget.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								rust/cli_player/src/ui_widgets/button_widget.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
use crate::ui_screens::utils::centered_rect_size;
 | 
			
		||||
use std::fmt::Display;
 | 
			
		||||
use tui::buffer::Buffer;
 | 
			
		||||
use tui::layout::Rect;
 | 
			
		||||
use tui::style::{Color, Style};
 | 
			
		||||
use tui::widgets::*;
 | 
			
		||||
 | 
			
		||||
pub struct ButtonWidget {
 | 
			
		||||
    is_hovered: bool,
 | 
			
		||||
    label: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ButtonWidget {
 | 
			
		||||
    pub fn new<D: Display>(label: D, is_hovered: bool) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            label: label.to_string(),
 | 
			
		||||
            is_hovered,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Widget for ButtonWidget {
 | 
			
		||||
    fn render(self, area: Rect, buf: &mut Buffer) {
 | 
			
		||||
        let label = format!(" {} ", self.label);
 | 
			
		||||
 | 
			
		||||
        let area = centered_rect_size(label.len() as u16, 1, area);
 | 
			
		||||
 | 
			
		||||
        let input = Paragraph::new(label.as_ref()).style(match &self.is_hovered {
 | 
			
		||||
            false => Style::default().bg(Color::DarkGray),
 | 
			
		||||
            true => Style::default().fg(Color::White).bg(Color::Yellow),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        input.render(area, buf);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										56
									
								
								rust/cli_player/src/ui_widgets/checkbox_widget.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								rust/cli_player/src/ui_widgets/checkbox_widget.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
use std::fmt::Display;
 | 
			
		||||
use tui::buffer::Buffer;
 | 
			
		||||
use tui::layout::Rect;
 | 
			
		||||
use tui::style::{Color, Style};
 | 
			
		||||
use tui::widgets::*;
 | 
			
		||||
 | 
			
		||||
pub struct CheckboxWidget {
 | 
			
		||||
    is_editing: bool,
 | 
			
		||||
    checked: bool,
 | 
			
		||||
    label: String,
 | 
			
		||||
    is_radio: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl CheckboxWidget {
 | 
			
		||||
    pub fn new<D: Display>(label: D, checked: bool, is_editing: bool) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            is_editing,
 | 
			
		||||
            checked,
 | 
			
		||||
            label: label.to_string(),
 | 
			
		||||
            is_radio: false,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn set_radio(mut self) -> Self {
 | 
			
		||||
        self.is_radio = true;
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Widget for CheckboxWidget {
 | 
			
		||||
    fn render(self, area: Rect, buf: &mut Buffer) {
 | 
			
		||||
        let paragraph = format!(
 | 
			
		||||
            "{}{}{} {}",
 | 
			
		||||
            match self.is_radio {
 | 
			
		||||
                true => "(",
 | 
			
		||||
                false => "[",
 | 
			
		||||
            },
 | 
			
		||||
            match self.checked {
 | 
			
		||||
                true => "X",
 | 
			
		||||
                false => " ",
 | 
			
		||||
            },
 | 
			
		||||
            match self.is_radio {
 | 
			
		||||
                true => ")",
 | 
			
		||||
                false => "]",
 | 
			
		||||
            },
 | 
			
		||||
            self.label
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let input = Paragraph::new(paragraph.as_ref()).style(match &self.is_editing {
 | 
			
		||||
            false => Style::default(),
 | 
			
		||||
            true => Style::default().fg(Color::Yellow),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        input.render(area, buf);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								rust/cli_player/src/ui_widgets/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								rust/cli_player/src/ui_widgets/mod.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
pub mod button_widget;
 | 
			
		||||
pub mod checkbox_widget;
 | 
			
		||||
pub mod text_editor_widget;
 | 
			
		||||
							
								
								
									
										46
									
								
								rust/cli_player/src/ui_widgets/text_editor_widget.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								rust/cli_player/src/ui_widgets/text_editor_widget.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
use std::fmt::Display;
 | 
			
		||||
use tui::buffer::Buffer;
 | 
			
		||||
use tui::layout::Rect;
 | 
			
		||||
use tui::style::{Color, Style};
 | 
			
		||||
use tui::widgets::{Block, Borders, Paragraph, Widget};
 | 
			
		||||
 | 
			
		||||
pub enum InputMode {
 | 
			
		||||
    Normal,
 | 
			
		||||
    Editing,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct TextEditorWidget {
 | 
			
		||||
    input_mode: InputMode,
 | 
			
		||||
    value: String,
 | 
			
		||||
    label: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TextEditorWidget {
 | 
			
		||||
    pub fn new<D: Display>(label: D, value: D, is_editing: bool) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            input_mode: match is_editing {
 | 
			
		||||
                true => InputMode::Editing,
 | 
			
		||||
                false => InputMode::Normal,
 | 
			
		||||
            },
 | 
			
		||||
            value: value.to_string(),
 | 
			
		||||
            label: label.to_string(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Widget for TextEditorWidget {
 | 
			
		||||
    fn render(self, area: Rect, buf: &mut Buffer) {
 | 
			
		||||
        let input = Paragraph::new(self.value.as_ref())
 | 
			
		||||
            .style(match &self.input_mode {
 | 
			
		||||
                InputMode::Normal => Style::default(),
 | 
			
		||||
                InputMode::Editing => Style::default().fg(Color::Yellow),
 | 
			
		||||
            })
 | 
			
		||||
            .block(
 | 
			
		||||
                Block::default()
 | 
			
		||||
                    .borders(Borders::ALL)
 | 
			
		||||
                    .title(self.label.as_ref()),
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
        input.render(area, buf);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user