diff options
| author | tslil clingman <> | 2021-01-09 22:42:12 -0500 |
|---|---|---|
| committer | tslil clingman <> | 2021-01-09 22:44:29 -0500 |
| commit | a0f3a7f8ba9036d1fcb18941a54077082f15cf3c (patch) | |
| tree | bb3943b7bc3cee704fbc7ad7c4e4c1ca0204d5f7 /src/tui.rs | |
| parent | 1cb3c0ea50ce55278413dfd368285cb622130a30 (diff) | |
Added .rustfmt.toml, tabs for indentation, spaces for alignment
Diffstat (limited to 'src/tui.rs')
| -rw-r--r-- | src/tui.rs | 1380 |
1 files changed, 695 insertions, 685 deletions
@@ -1,18 +1,18 @@ /* - This file is part of Takwrap. + This file is part of Takwrap. - Takwrap is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + Takwrap is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - Takwrap is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + Takwrap is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Takwrap. If not, see <https://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with Takwrap. If not, see <https://www.gnu.org/licenses/>. */ extern crate pancurses; @@ -29,779 +29,789 @@ use crate::parser::*; #[derive(PartialEq)] pub enum TUIResult { - Undo, - Quit, - Save, - SwitchElement, - Raw(String), + Undo, + Quit, + Save, + SwitchElement, + Raw(String), } pub struct GameLog { - action_window: Window, - pieces_window: Window, - has_colours: bool, - white_colour: u8, - black_colour: u8, - num_lines: usize, - offset: usize, - action_lines: Vec<String>, + action_window: Window, + pieces_window: Window, + has_colours: bool, + white_colour: u8, + black_colour: u8, + num_lines: usize, + offset: usize, + action_lines: Vec<String>, } impl GameLog { - pub fn new( - ypos: i32, - xpos: i32, - height: i32, - width: i32, - has_colours: bool, - white_colour: u8, - black_colour: u8, - ) -> GameLog { - let gl = GameLog { - pieces_window: newwin(4, width, ypos, xpos), - action_window: newwin(height - 5, width, ypos + 5, xpos), - has_colours, - white_colour, - black_colour, - num_lines: (height - 7) as usize, - offset: 0, - action_lines: Vec::new(), - }; + pub fn new( + ypos: i32, + xpos: i32, + height: i32, + width: i32, + has_colours: bool, + white_colour: u8, + black_colour: u8, + ) -> GameLog { + let gl = GameLog { + pieces_window: newwin(4, width, ypos, xpos), + action_window: newwin(height - 5, width, ypos + 5, xpos), + has_colours, + white_colour, + black_colour, + num_lines: (height - 7) as usize, + offset: 0, + action_lines: Vec::new(), + }; - gl.action_window.keypad(true); - gl.action_window.nodelay(false); - gl - } + gl.action_window.keypad(true); + gl.action_window.nodelay(false); + gl + } - pub fn update(&mut self, game: &Game) { - self.pieces_window.clear(); + pub fn update(&mut self, game: &Game) { + self.pieces_window.clear(); - if self.has_colours { - self.pieces_window.attrset(ColorPair(self.white_colour)); - } - self.pieces_window.addstr(format!( - "W: {:2}", - game.get_pieces(Player::White, Stone::Flat) - )); + if self.has_colours { + self.pieces_window.attrset(ColorPair(self.white_colour)); + } + self.pieces_window.addstr(format!( + "W: {:2}", + game.get_pieces(Player::White, Stone::Flat) + )); - self.pieces_window.attrset(Attribute::Normal); - self.pieces_window.addstr(" "); + self.pieces_window.attrset(Attribute::Normal); + self.pieces_window.addstr(" "); - if self.has_colours { - self.pieces_window.attrset(ColorPair(self.black_colour)); - } - self.pieces_window.addstr(format!( - "B: {:2}", - game.get_pieces(Player::Black, Stone::Flat), - )); + if self.has_colours { + self.pieces_window.attrset(ColorPair(self.black_colour)); + } + self.pieces_window.addstr(format!( + "B: {:2}", + game.get_pieces(Player::Black, Stone::Flat), + )); - self.pieces_window.attrset(Attribute::Normal); + self.pieces_window.attrset(Attribute::Normal); - self.pieces_window - .addstr(format!(" Variant: {}", game.get_start_type().to_string())); + self + .pieces_window + .addstr(format!(" Variant: {}", game.get_start_type().to_string())); - self.pieces_window.mv(1, 0); + self.pieces_window.mv(1, 0); - if self.has_colours { - self.pieces_window.attrset(ColorPair(self.white_colour)); - } - self.pieces_window.addstr(format!( - "WC: {}", - game.get_pieces(Player::White, Stone::Capstone) - )); + if self.has_colours { + self.pieces_window.attrset(ColorPair(self.white_colour)); + } + self.pieces_window.addstr(format!( + "WC: {}", + game.get_pieces(Player::White, Stone::Capstone) + )); - self.pieces_window.attrset(Attribute::Normal); - self.pieces_window.addstr(" "); + self.pieces_window.attrset(Attribute::Normal); + self.pieces_window.addstr(" "); - if self.has_colours { - self.pieces_window.attrset(ColorPair(self.black_colour)); - } - self.pieces_window.addstr(format!( - "BC: {}", - game.get_pieces(Player::Black, Stone::Capstone), - )); - self.pieces_window.attrset(Attribute::Normal); + if self.has_colours { + self.pieces_window.attrset(ColorPair(self.black_colour)); + } + self.pieces_window.addstr(format!( + "BC: {}", + game.get_pieces(Player::Black, Stone::Capstone), + )); + self.pieces_window.attrset(Attribute::Normal); - self.pieces_window - .addstr(format!(" Ply: {}", game.get_ply() + 1)); + self + .pieces_window + .addstr(format!(" Ply: {}", game.get_ply() + 1)); - self.pieces_window.mv(3, 0); - self.pieces_window.addstr("Active player: "); - match game.get_current_player() { - Player::Black => { - if self.has_colours { - self.pieces_window.attrset(ColorPair(self.black_colour)); - } - } - Player::White => { - if self.has_colours { - self.pieces_window.attrset(ColorPair(self.white_colour)); - } - } - } - self.pieces_window.addstr(game.get_current_player_name()); + self.pieces_window.mv(3, 0); + self.pieces_window.addstr("Active player: "); + match game.get_current_player() { + Player::Black => { + if self.has_colours { + self.pieces_window.attrset(ColorPair(self.black_colour)); + } + } + Player::White => { + if self.has_colours { + self.pieces_window.attrset(ColorPair(self.white_colour)); + } + } + } + self.pieces_window.addstr(game.get_current_player_name()); - let new_lines = game.get_action_lines(); - if new_lines.len() > self.num_lines { - self.offset = new_lines.len() - self.num_lines; - } else { - self.offset = 0; - } - self.action_lines = new_lines.clone(); - self.list_actions(); + let new_lines = game.get_action_lines(); + if new_lines.len() > self.num_lines { + self.offset = new_lines.len() - self.num_lines; + } else { + self.offset = 0; + } + self.action_lines = new_lines.clone(); + self.list_actions(); - self.pieces_window.refresh(); - } + self.pieces_window.refresh(); + } - fn list_actions(&self) { - self.action_window.clear(); - self.action_window.draw_box(0, 0); - let mut y = 1; - for i in 0..self.num_lines { - if let Some(line) = self.action_lines.get(i + self.offset) { - self.action_window.mv(y, 2); - self.action_window.addstr(line); - y += 1; - } - } - self.action_window.refresh(); - self.action_window.mv(1, 2); - } + fn list_actions(&self) { + self.action_window.clear(); + self.action_window.draw_box(0, 0); + let mut y = 1; + for i in 0..self.num_lines { + if let Some(line) = self.action_lines.get(i + self.offset) { + self.action_window.mv(y, 2); + self.action_window.addstr(line); + y += 1; + } + } + self.action_window.refresh(); + self.action_window.mv(1, 2); + } - pub fn read_action(&mut self) -> TUIResult { - loop { - self.list_actions(); - if let Some(inp) = self.action_window.getch() { - match inp { - KeyUp => { - if self.offset > 0 { - self.offset -= 1; - } - } - KeyDown => { - if self.offset + self.num_lines < self.action_lines.len() { - self.offset += 1; - } - } - Character('\t') => return TUIResult::SwitchElement, - Character('U') => return TUIResult::Undo, - Character('Q') => return TUIResult::Quit, - Character('S') => return TUIResult::Save, - _ => (), - } - } - } - } + pub fn read_action(&mut self) -> TUIResult { + loop { + self.list_actions(); + if let Some(inp) = self.action_window.getch() { + match inp { + KeyUp => { + if self.offset > 0 { + self.offset -= 1; + } + } + KeyDown => { + if self.offset + self.num_lines < self.action_lines.len() { + self.offset += 1; + } + } + Character('\t') => return TUIResult::SwitchElement, + Character('U') => return TUIResult::Undo, + Character('Q') => return TUIResult::Quit, + Character('S') => return TUIResult::Save, + _ => (), + } + } + } + } } pub struct BoardTUI { - board_window: Window, - cell_windows: Vec<Window>, - size: u8, - cell_height: u8, - cell_width: u8, - hoff: i32, - cur_cell: Position, - has_colours: bool, - white_colour: u8, - black_colour: u8, + board_window: Window, + cell_windows: Vec<Window>, + size: u8, + cell_height: u8, + cell_width: u8, + hoff: i32, + cur_cell: Position, + has_colours: bool, + white_colour: u8, + black_colour: u8, } impl BoardTUI { - fn draw_grid(&self) { - let s: i32 = self.size as i32; - let h: i32 = self.cell_height as i32; - let w: i32 = self.cell_width as i32; - for y in 0..h * s + 1 { - for x in 0..w * s + 1 { - if y % h == 0 { - if x % w == 0 { - self.board_window.mvaddch(y, x + self.hoff, '+'); - } else { - self.board_window.mvaddch(y, x + self.hoff, '-'); - } - } else if x % w == 0 { - self.board_window.mvaddch(y, x + self.hoff, '|'); - } - } - } - for y in 0..s { - self.board_window - .mvaddstr(y * h + h / 2, 0, format!("{}.", s - y)); - } - for x in 0..s { - self.board_window.mvaddstr( - s * h + 1, - w * x + w / 2 + self.hoff, - format!("{:x}.", x + 10), - ); - } - self.board_window.refresh(); - } + fn draw_grid(&self) { + let s: i32 = self.size as i32; + let h: i32 = self.cell_height as i32; + let w: i32 = self.cell_width as i32; + for y in 0..h * s + 1 { + for x in 0..w * s + 1 { + if y % h == 0 { + if x % w == 0 { + self.board_window.mvaddch(y, x + self.hoff, '+'); + } else { + self.board_window.mvaddch(y, x + self.hoff, '-'); + } + } else if x % w == 0 { + self.board_window.mvaddch(y, x + self.hoff, '|'); + } + } + } + for y in 0..s { + self + .board_window + .mvaddstr(y * h + h / 2, 0, format!("{}.", s - y)); + } + for x in 0..s { + self.board_window.mvaddstr( + s * h + 1, + w * x + w / 2 + self.hoff, + format!("{:x}.", x + 10), + ); + } + self.board_window.refresh(); + } - fn pos_to_idx(&self, pos: &Position) -> usize { - let y = pos.y as usize; - let x = pos.x as usize; - x + y * (self.size as usize) - } + fn pos_to_idx(&self, pos: &Position) -> usize { + let y = pos.y as usize; + let x = pos.x as usize; + x + y * (self.size as usize) + } - fn mv_to_cell(&self, pos: &Position, line: i32) { - if let Some(win) = self.cell_windows.get(self.pos_to_idx(pos)) { - win.mv(line, 0); - win.refresh(); - } - } + fn mv_to_cell(&self, pos: &Position, line: i32) { + if let Some(win) = self.cell_windows.get(self.pos_to_idx(pos)) { + win.mv(line, 0); + win.refresh(); + } + } - fn draw_stone(&self, win: &Window, top: bool, buried: bool, player: &Player, stone: &Stone) { - if self.has_colours && (!buried) { - match player { - Player::Black => win.attron(ColorPair(self.black_colour)), - Player::White => win.attron(ColorPair(self.white_colour)), - }; - if top { - win.addch(match stone { - Stone::Flat => '#', - Stone::Standing => '/', - Stone::Capstone => '*', - }); - } else { - win.addstr(format!("{}", player)); - } - win.attrset(Attribute::Normal); - } else { - if buried { - win.attron(Attribute::Underline); - } - win.addstr(format!("{}", player)); - if top { - win.addstr(format!("{}", stone)); - } - } - } + fn draw_stone(&self, win: &Window, top: bool, buried: bool, player: &Player, stone: &Stone) { + if self.has_colours && (!buried) { + match player { + Player::Black => win.attron(ColorPair(self.black_colour)), + Player::White => win.attron(ColorPair(self.white_colour)), + }; + if top { + win.addch(match stone { + Stone::Flat => '#', + Stone::Standing => '/', + Stone::Capstone => '*', + }); + } else { + win.addstr(format!("{}", player)); + } + win.attrset(Attribute::Normal); + } else { + if buried { + win.attron(Attribute::Underline); + } + win.addstr(format!("{}", player)); + if top { + win.addstr(format!("{}", stone)); + } + } + } - fn draw_stack(&self, pos: &Position, stack: &Stack) { - if let Some(win) = self.cell_windows.get(self.pos_to_idx(pos)) { - win.clear(); - let height = stack.len() as i32; - if height > 0 { - let carry_capacity = self.size; + fn draw_stack(&self, pos: &Position, stack: &Stack) { + if let Some(win) = self.cell_windows.get(self.pos_to_idx(pos)) { + win.clear(); + let height = stack.len() as i32; + if height > 0 { + let carry_capacity = self.size; - let my = win.get_max_y(); - let mut cy = 0; - let mut cx = 0; + let my = win.get_max_y(); + let mut cy = 0; + let mut cx = 0; - for i in 0..height { - let piece = &stack[(height - i - 1) as usize]; - self.draw_stone( - win, - i == 0, - i >= carry_capacity as i32, - &piece.player, - &piece.stone, - ); - cy += 1; - if (cy >= my) && (i + 1 < height) { - cx += 1; - if i + my - 1 >= height { - cy = i + my - height + 1; - } else { - cy = 1; - } - win.mv(0, cx); - win.attrset(Attribute::Normal); - win.addch('v'); - } - win.mv(cy, cx); - } - } - win.refresh(); - } - } + for i in 0..height { + let piece = &stack[(height - i - 1) as usize]; + self.draw_stone( + win, + i == 0, + i >= carry_capacity as i32, + &piece.player, + &piece.stone, + ); + cy += 1; + if (cy >= my) && (i + 1 < height) { + cx += 1; + if i + my - 1 >= height { + cy = i + my - height + 1; + } else { + cy = 1; + } + win.mv(0, cx); + win.attrset(Attribute::Normal); + win.addch('v'); + } + win.mv(cy, cx); + } + } + win.refresh(); + } + } - pub fn update(&self, game: &Game, squares: Vec<Position>) { - // Is this really the `best' way? - assert!(game.get_size() == self.size); - for p in squares { - if let Some(stack) = game.query_square(&p) { - self.draw_stack(&p, stack); - } - } - // Prevent redraw of the grid itself? - self.board_window.untouch(); - } + pub fn update(&self, game: &Game, squares: Vec<Position>) { + // Is this really the `best' way? + assert!(game.get_size() == self.size); + for p in squares { + if let Some(stack) = game.query_square(&p) { + self.draw_stack(&p, stack); + } + } + // Prevent redraw of the grid itself? + self.board_window.untouch(); + } - pub fn new( - ypos: i32, - xpos: i32, - size: u8, - cell_height: u8, - cell_width: u8, - hoff: u8, - has_colours: bool, - white_colour: u8, - black_colour: u8, - ) -> BoardTUI { - let hoff = hoff as i32; - let s: i32 = size as i32; - let h: i32 = cell_height as i32; - let w: i32 = cell_width as i32; + pub fn new( + ypos: i32, + xpos: i32, + size: u8, + cell_height: u8, + cell_width: u8, + hoff: u8, + has_colours: bool, + white_colour: u8, + black_colour: u8, + ) -> BoardTUI { + let hoff = hoff as i32; + let s: i32 = size as i32; + let h: i32 = cell_height as i32; + let w: i32 = cell_width as i32; - let board_window = newwin(h * s + 3, w * s + 3 + hoff, ypos, xpos); + let board_window = newwin(h * s + 3, w * s + 3 + hoff, ypos, xpos); - let mut cell_windows: Vec<Window> = Vec::new(); - for i in 0..s * s { - let y: i32 = i / s; - let x: i32 = i % s; - cell_windows.push(newwin( - h - 1, - w - 1, - (s - y - 1) * h + 1 + ypos, - hoff + x * w + 1 + xpos, - )); - } + let mut cell_windows: Vec<Window> = Vec::new(); + for i in 0..s * s { + let y: i32 = i / s; + let x: i32 = i % s; + cell_windows.push(newwin( + h - 1, + w - 1, + (s - y - 1) * h + 1 + ypos, + hoff + x * w + 1 + xpos, + )); + } - let bg = BoardTUI { - board_window, - cell_windows, - size, - cell_height, - cell_width, - hoff, - cur_cell: Position { x: 0, y: 0 }, - has_colours, - black_colour, - white_colour, - }; + let bg = BoardTUI { + board_window, + cell_windows, + size, + cell_height, + cell_width, + hoff, + cur_cell: Position { x: 0, y: 0 }, + has_colours, + black_colour, + white_colour, + }; - bg.board_window.keypad(true); - bg.board_window.nodelay(false); + bg.board_window.keypad(true); + bg.board_window.nodelay(false); - bg.draw_grid(); + bg.draw_grid(); - bg.mv_to_cell(&bg.cur_cell, 0); - bg.board_window.refresh(); - bg - } + bg.mv_to_cell(&bg.cur_cell, 0); + bg.board_window.refresh(); + bg + } } pub struct ActionEntry { - window: Window, - max_len: usize, - xstart: i32, + window: Window, + max_len: usize, + xstart: i32, } impl ActionEntry { - pub fn clear_entry_area(&self) { - self.window.mv(0, self.xstart); - for _i in 0..self.max_len { - self.window.addch('_'); - } + pub fn clear_entry_area(&self) { + self.window.mv(0, self.xstart); + for _i in 0..self.max_len { + self.window.addch('_'); + } - self.window.mv(0, self.xstart); - self.window.refresh(); - } + self.window.mv(0, self.xstart); + self.window.refresh(); + } - pub fn new(ypos: i32, xpos: i32, max_len: usize) -> ActionEntry { - let txt = "Enter action: "; - let xstart = txt.len() as i32; - let width = max_len as i32 + xstart + 1; + pub fn new(ypos: i32, xpos: i32, max_len: usize) -> ActionEntry { + let txt = "Enter action: "; + let xstart = txt.len() as i32; + let width = max_len as i32 + xstart + 1; - let ae = ActionEntry { - window: newwin(1, width, ypos, xpos), - max_len, - xstart, - }; + let ae = ActionEntry { + window: newwin(1, width, ypos, xpos), + max_len, + xstart, + }; - ae.window.nodelay(false); - ae.window.keypad(true); + ae.window.nodelay(false); + ae.window.keypad(true); - ae.window.addstr(txt); - ae.clear_entry_area(); - ae - } + ae.window.addstr(txt); + ae.clear_entry_area(); + ae + } - pub fn read_action(&self) -> TUIResult { - self.window.mv(0, self.xstart); - self.window.refresh(); + pub fn read_action(&self) -> TUIResult { + self.window.mv(0, self.xstart); + self.window.refresh(); - let mut result = String::new(); - loop { - if let Some(inp) = self.window.getch() { - match inp { - Character('\t') => return TUIResult::SwitchElement, - Character('\n') => break, + let mut result = String::new(); + loop { + if let Some(inp) = self.window.getch() { + match inp { + Character('\t') => return TUIResult::SwitchElement, + Character('\n') => break, - Character(c) => { - // Annoyingly there are two backspace possibilities - let ascii = c as usize; - if !result.is_empty() && (ascii == 127) || (ascii == 8) { - result.pop(); - let (y, x) = (self.window.get_cur_y(), self.window.get_cur_x()); - self.window.mv(y, x - 1); - self.window.addch('_'); - self.window.mv(y, x - 1); - } else { - if (result.len() < self.max_len) && (ascii > 32) && (ascii < 127) { - result.push(c); - self.window.addch(c); - } - } - } - KeyBackspace => { - if !result.is_empty() { - result.pop(); - let (y, x) = (self.window.get_cur_y(), self.window.get_cur_x()); - self.window.mv(y, x - 1); - self.window.addch('_'); - self.window.mv(y, x - 1); - } - } + Character(c) => { + // Annoyingly there are two backspace possibilities + let ascii = c as usize; + if !result.is_empty() && (ascii == 127) || (ascii == 8) { + result.pop(); + let (y, x) = (self.window.get_cur_y(), self.window.get_cur_x()); + self.window.mv(y, x - 1); + self.window.addch('_'); + self.window.mv(y, x - 1); + } else { + if (result.len() < self.max_len) && (ascii > 32) && (ascii < 127) { + result.push(c); + self.window.addch(c); + } + } + } + KeyBackspace => { + if !result.is_empty() { + result.pop(); + let (y, x) = (self.window.get_cur_y(), self.window.get_cur_x()); + self.window.mv(y, x - 1); + self.window.addch('_'); + self.window.mv(y, x - 1); + } + } - KeyEnter => break, - _ => (), - }; - } - self.window.refresh(); - } - self.clear_entry_area(); - return TUIResult::Raw(result); - } + KeyEnter => break, + _ => (), + }; + } + self.window.refresh(); + } + self.clear_entry_area(); + return TUIResult::Raw(result); + } } pub struct MessageLog { - window: Window, - has_colours: bool, - red_colour: u8, + window: Window, + has_colours: bool, + red_colour: u8, } impl MessageLog { - pub fn new( - ypos: i32, - xpos: i32, - height: i32, - width: i32, - has_colours: bool, - red_colour: u8, - ) -> MessageLog { - MessageLog { - window: newwin(height, width, ypos, xpos), - has_colours: has_colours, - red_colour: red_colour, - } - } + pub fn new( + ypos: i32, + xpos: i32, + height: i32, + width: i32, + has_colours: bool, + red_colour: u8, + ) -> MessageLog { + MessageLog { + window: newwin(height, width, ypos, xpos), + has_colours: has_colours, + red_colour: red_colour, + } + } - pub fn log_message(&self, str: String) { - self.window.clear(); - if self.has_colours { - self.window.attrset(Attribute::Normal); - } - self.window.addstr(str); - self.window.refresh(); - } + pub fn log_message(&self, str: String) { + self.window.clear(); + if self.has_colours { + self.window.attrset(Attribute::Normal); + } + self.window.addstr(str); + self.window.refresh(); + } - pub fn log_error(&self, str: String) { - self.window.clear(); - if self.has_colours { - self.window.attrset(ColorPair(self.red_colour)); - } - self.window.addstr(str); - self.window.refresh(); - } + pub fn log_error(&self, str: String) { + self.window.clear(); + if self.has_colours { + self.window.attrset(ColorPair(self.red_colour)); + } + self.window.addstr(str); + self.window.refresh(); + } } enum InputSource { - Player, - Log, + Player, + Log, } const ACTION_HEADER: &str = "Enter action in PTN"; const LOG_HEADER: &str = "U to undo a turn | <UP>/<DOWN> to scroll | S to save PTN | Q to quit"; pub struct TUI { - screen: Window, - game_log: GameLog, - pub message_log: MessageLog, - action_entry: ActionEntry, - board_tui: BoardTUI, - input_source: InputSource, + screen: Window, + game_log: GameLog, + pub message_log: MessageLog, + action_entry: ActionEntry, + board_tui: BoardTUI, + input_source: InputSource, } impl TUI { - fn write_header(&self, header: &str) { - self.screen.mv(0, 0); - self.screen.clrtoeol(); - self.screen.addstr(format!( - "takwrap {} | <TAB> to switch TUI element | {}", - env!("CARGO_PKG_VERSION").to_string(), - header - )); - self.screen.mvchgat(0, 0, -1, A_REVERSE, -1); - self.screen.refresh(); - } + fn write_header(&self, header: &str) { + self.screen.mv(0, 0); + self.screen.clrtoeol(); + self.screen.addstr(format!( + "takwrap {} | <TAB> to switch TUI element | {}", + env!("CARGO_PKG_VERSION").to_string(), + header + )); + self.screen.mvchgat(0, 0, -1, A_REVERSE, -1); + self.screen.refresh(); + } - fn save(&self, game: &Game) { - let file = File::create(format!("Game_{}.ptn", game.get_date_string())); + fn save(&self, game: &Game) { + let file = File::create(format!("Game_{}.ptn", game.get_date_string())); - match file { - Err(e) => { - self.message_log - .log_error(format!("Unable to open PTN file for writing: {}", e)); - } - Ok(file) => { - if let Err(e) = write!(&file, "{}", game.to_string()) { - self.message_log - .log_error(format!("Unable to write PTN to file: {}", e)); - } else { - self.message_log.log_message(String::from("PTN saved.")); - } - } - } - } + match file { + Err(e) => { + self + .message_log + .log_error(format!("Unable to open PTN file for writing: {}", e)); + } + Ok(file) => { + if let Err(e) = write!(&file, "{}", game.to_string()) { + self + .message_log + .log_error(format!("Unable to write PTN to file: {}", e)); + } else { + self.message_log.log_message(String::from("PTN saved.")); + } + } + } + } - pub fn new(game: &Game, warning: String) -> TUI { - let screen = initscr(); - cbreak(); - noecho(); - curs_set(2); + pub fn new(game: &Game, warning: String) -> TUI { + let screen = initscr(); + cbreak(); + noecho(); + curs_set(2); - let has_colours = has_colors(); - let (black_colour, white_colour, red_colour): (u8, u8, u8) = (1, 2, 3); + let has_colours = has_colors(); + let (black_colour, white_colour, red_colour): (u8, u8, u8) = (1, 2, 3); - if has_colours { - start_color(); - use_default_colors(); - init_pair(black_colour as i16, -1, COLOR_RED); - init_pair(white_colour as i16, -1, COLOR_BLUE); - init_pair(red_colour as i16, COLOR_RED, -1); - } + if has_colours { + start_color(); + use_default_colors(); + init_pair(black_colour as i16, -1, COLOR_RED); + init_pair(white_colour as i16, -1, COLOR_BLUE); + init_pair(red_colour as i16, COLOR_RED, -1); + } - let voff = 2; + let voff = 2; - let height = screen.get_max_y() - voff; + let height = screen.get_max_y() - voff; - screen.refresh(); + screen.refresh(); - let cell_height = 4; - let cell_width = 8; - let hoff = 3; - let size = game.get_size(); + let cell_height = 4; + let cell_width = 8; + let hoff = 3; + let size = game.get_size(); - let board_bottom = voff + (size * cell_height + 3) as i32; - let board_right = (hoff + size * cell_width + 3) as i32; + let board_bottom = voff + (size * cell_height + 3) as i32; + let board_right = (hoff + size * cell_width + 3) as i32; - let board_tui = BoardTUI::new( - voff, - 0, - size, - cell_height, - cell_width, - hoff, - has_colours, - white_colour, - black_colour, - ); + let board_tui = BoardTUI::new( + voff, + 0, + size, + cell_height, + cell_width, + hoff, + has_colours, + white_colour, + black_colour, + ); - let game_log = GameLog::new( - voff, - board_right, - height - 2, - 30, - has_colours, - white_colour, - black_colour, - ); + let game_log = GameLog::new( + voff, + board_right, + height - 2, + 30, + has_colours, + white_colour, + black_colour, + ); - // Need room for '8___011111111', for example - let action_entry = ActionEntry::new(board_bottom, 0, 13); + // Need room for '8___011111111', for example + let action_entry = ActionEntry::new(board_bottom, 0, 13); - let message_log = MessageLog::new( - board_bottom + 2, - 0, - height - board_bottom - 1, - board_right, - has_colours, - red_colour, - ); + let message_log = MessageLog::new( + board_bottom + 2, + 0, + height - board_bottom - 1, + board_right, + has_colours, + red_colour, + ); - let mut tui = TUI { - screen, - game_log, - message_log, - action_entry, - board_tui, - input_source: InputSource::Player, - }; + let mut tui = TUI { + screen, + game_log, + message_log, + action_entry, + board_tui, + input_source: InputSource::Player, + }; - tui.write_header(ACTION_HEADER); - tui.message_log.log_error(warning); - tui.game_log.update(game); + tui.write_header(ACTION_HEADER); + tui.message_log.log_error(warning); + tui.game_log.update(game); - tui - } + tui + } - pub fn query_input( - &mut self, - game: &Game, - call_proc: bool, - p1_white: bool, - engine: &str, - ) -> Result<TUIResult, String> { - match self.input_source { - InputSource::Player => { - let player = game.get_current_player(); + pub fn query_input( + &mut self, + game: &Game, + call_proc: bool, + p1_white: bool, + engine: &str, + ) -> Result<TUIResult, String> { + match self.input_source { + InputSource::Player => { + let player = game.get_current_player(); - let inp = match player { - Player::Black => { - if call_proc && p1_white { - self.message_log - .log_message(String::from("Opponent is thinking...")); - consult_next_action(&game, &engine) - } else { - Ok(self.action_entry.read_action()) - } - } - Player::White => { - if call_proc && (!p1_white) { - self.message_log - .log_message(String::from("Opponent is thinking...")); - consult_next_action(&game, &engine) - } else { - Ok(self.action_entry.read_action()) - } - } - }; + let inp = match player { + Player::Black => { + if call_proc && p1_white { + self + .message_log + .log_message(String::from("Opponent is thinking...")); + consult_next_action(&game, &engine) + } else { + Ok(self.action_entry.read_action()) + } + } + Player::White => { + if call_proc && (!p1_white) { + self + .message_log + .log_message(String::from("Opponent is thinking...")); + consult_next_action(&game, &engine) + } else { + Ok(self.action_entry.read_action()) + } + } + }; - match inp { - Err(e) => Err(format!("Error: {}", e)), - Ok(ok) => Ok(ok), - } - } - InputSource::Log => Ok(self.game_log.read_action()), - } - } + match inp { + Err(e) => Err(format!("Error: {}", e)), + Ok(ok) => Ok(ok), + } + } + InputSource::Log => Ok(self.game_log.read_action()), + } + } - pub fn handle_input( - &mut self, - game: &mut Game, - call_proc: bool, - p1_white: bool, - input: Result<TUIResult, String>, - ) -> bool { - let player = game.get_current_player(); - let engine_turn = call_proc - && ((p1_white && player == Player::Black) || ((!p1_white) && player == Player::White)); + pub fn handle_input( + &mut self, + game: &mut Game, + call_proc: bool, + p1_white: bool, + input: Result<TUIResult, String>, + ) -> bool { + let player = game.get_current_player(); + let engine_turn = call_proc + && ((p1_white && player == Player::Black) || ((!p1_white) && player == Player::White)); - match input { - Err(e) => { - if engine_turn { - self.message_log - .log_error(format!("Unrecoverable error: {}", e)); - return false; - } - } - Ok(tui_result) => match tui_result { - TUIResult::Quit => { - self.message_log - .log_message(String::from("Press any key to quit.")); - self.screen.getch(); - return false; - } - TUIResult::Save => { - self.save(game); - self.screen.getch(); - return false; - } - TUIResult::SwitchElement => match self.input_source { - InputSource::Player => { - self.input_source = InputSource::Log; - self.write_header(LOG_HEADER); - } - InputSource::Log => { - self.input_source = InputSource::Player; - self.write_header(ACTION_HEADER); - } - }, - TUIResult::Undo => match game.undo() { - Ok(pos_vec) => { - self.message_log - .log_message(String::from("Game undone by one turn.")); - self.board_tui.update(&game, pos_vec); - self.game_log.update(&game); - } - Err(err) => { - self.message_log.log_error(err); - } - }, - TUIResult::Raw(raw) => { - let stone_owner = game.get_stone_owner(); - let act = parse_action(stone_owner, &raw); - match act { - Err(err) => { - self.message_log - .log_error(format!("Input \"{}\": {}", raw, err)); - if engine_turn { - return false; - } - } - Ok(act) => { - let pn = game.get_current_player_name(); - self.message_log.log_message(format!( - "{} performs {}{}", - pn, - act, - if stone_owner != player { - format!(" with a {} stone.", stone_owner) - } else { - String::from(".") - } - )); - let act_string = act.to_string(); - match game.perform_action(act) { - Err(e) => { - if engine_turn { - self.message_log.log_error(String::from( - "Error: external and internal game states disagree. Press any key to quit.", - )); - self.screen.getch(); - return false; - } else { - self.message_log.log_error(format!( - "Cannot perform \"{}\": {}", - act_string, e - )); - } - } + match input { + Err(e) => { + if engine_turn { + self + .message_log + .log_error(format!("Unrecoverable error: {}", e)); + return false; + } + } + Ok(tui_result) => match tui_result { + TUIResult::Quit => { + self + .message_log + .log_message(String::from("Press any key to quit.")); + self.screen.getch(); + return false; + } + TUIResult::Save => { + self.save(game); + self.screen.getch(); + return false; + } + TUIResult::SwitchElement => match self.input_source { + InputSource::Player => { + self.input_source = InputSource::Log; + self.write_header(LOG_HEADER); + } + InputSource::Log => { + self.input_source = InputSource::Player; + self.write_header(ACTION_HEADER); + } + }, + TUIResult::Undo => match game.undo() { + Ok(pos_vec) => { + self + .message_log + .log_message(String::from("Game undone by one turn.")); + self.board_tui.update(&game, pos_vec); + self.game_log.update(&game); + } + Err(err) => { + self.message_log.log_error(err); + } + }, + TUIResult::Raw(raw) => { + let stone_owner = game.get_stone_owner(); + let act = parse_action(stone_owner, &raw); + match act { + Err(err) => { + self + .message_log + .log_error(format!("Input \"{}\": {}", raw, err)); + if engine_turn { + return false; + } + } + Ok(act) => { + let pn = game.get_current_player_name(); + self.message_log.log_message(format!( + "{} performs {}{}", + pn, + act, + if stone_owner != player { + format!(" with a {} stone.", stone_owner) + } else { + String::from(".") + } + )); + let act_string = act.to_string(); + match game.perform_action(act) { + Err(e) => { + if engine_turn { + self.message_log.log_error(String::from( + "Error: external and internal game states disagree. Press any key to quit.", + )); + self.screen.getch(); + return false; + } else { + self + .message_log + .log_error(format!("Cannot perform \"{}\": {}", act_string, e)); + } + } - Ok((pos_vec, win)) => { - self.board_tui.update(&game, pos_vec); - self.game_log.update(&game); - if let Some(w) = win { - self.message_log.log_message(format!( - "Game over: {}\nPress S to save PTN and quit, or Q to quit.", - w - )); - loop { - if let Some(inp) = self.screen.getch() { - match inp { - Character('S') => { - self.save(game); - return false; - } - Character('Q') => { - return false; - } - _ => (), - } - } - } - } - } - } - } - } - } - }, - } - return true; - } + Ok((pos_vec, win)) => { + self.board_tui.update(&game, pos_vec); + self.game_log.update(&game); + if let Some(w) = win { + self.message_log.log_message(format!( + "Game over: {}\nPress S to save PTN and quit, or Q to quit.", + w + )); + loop { + if let Some(inp) = self.screen.getch() { + match inp { + Character('S') => { + self.save(game); + return false; + } + Character('Q') => { + return false; + } + _ => (), + } + } + } + } + } + } + } + } + } + }, + } + return true; + } } |
