diff options
Diffstat (limited to 'src/gui')
| -rw-r--r-- | src/gui/boardwidget.rs | 426 | ||||
| -rw-r--r-- | src/gui/mod.rs | 182 |
2 files changed, 304 insertions, 304 deletions
diff --git a/src/gui/boardwidget.rs b/src/gui/boardwidget.rs index d831ed1..2708f21 100644 --- a/src/gui/boardwidget.rs +++ b/src/gui/boardwidget.rs @@ -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/>. */ use fltk::{app::*, button::*, draw::*}; @@ -25,240 +25,240 @@ use crate::game::*; // when rendering in button.draw2(...) later. We do, however, need to // use compute_square_size because the widget may be resized. struct BoardRenderer { - even_square_colour: Color, - odd_square_colour: Color, - black_colour: Color, - white_colour: Color, - stone_size: f32, - game_size: i32, - frame_pad: i32, - xorg: i32, - yorg: i32, + even_square_colour: Color, + odd_square_colour: Color, + black_colour: Color, + white_colour: Color, + stone_size: f32, + game_size: i32, + frame_pad: i32, + xorg: i32, + yorg: i32, } impl BoardRenderer { - fn default() -> BoardRenderer { - BoardRenderer { - // Sandy brown - odd_square_colour: Color::from_rgb(244, 164, 96), - // Moccasin - even_square_colour: Color::from_rgb(255, 228, 181), - // Colours for pieces - black_colour: Color::from_rgb(178, 34, 34), - white_colour: Color::from_rgb(250, 235, 215), - // Gap between stones and edged of square - stone_size: 0.8, - // Defaults - game_size: 5, - frame_pad: 5, - xorg: 0, - yorg: 0, - } - } + fn default() -> BoardRenderer { + BoardRenderer { + // Sandy brown + odd_square_colour: Color::from_rgb(244, 164, 96), + // Moccasin + even_square_colour: Color::from_rgb(255, 228, 181), + // Colours for pieces + black_colour: Color::from_rgb(178, 34, 34), + white_colour: Color::from_rgb(250, 235, 215), + // Gap between stones and edged of square + stone_size: 0.8, + // Defaults + game_size: 5, + frame_pad: 5, + xorg: 0, + yorg: 0, + } + } - fn with_size(mut self, size: i32) -> BoardRenderer { - self.game_size = size; - return self; - } + fn with_size(mut self, size: i32) -> BoardRenderer { + self.game_size = size; + return self; + } - fn with_org(mut self, button: &Button) -> BoardRenderer { - let x0 = button.x(); - let y0 = button.y(); - self.xorg = x0 + self.frame_pad; - self.yorg = y0 + self.frame_pad; - return self; - } + fn with_org(mut self, button: &Button) -> BoardRenderer { + let x0 = button.x(); + let y0 = button.y(); + self.xorg = x0 + self.frame_pad; + self.yorg = y0 + self.frame_pad; + return self; + } - fn compute_square_size(&self, button: &Button) -> i32 { - let board_size = i32::min(button.width(), button.height()) - self.frame_pad * 2; - return board_size / self.game_size; - } + fn compute_square_size(&self, button: &Button) -> i32 { + let board_size = i32::min(button.width(), button.height()) - self.frame_pad * 2; + return board_size / self.game_size; + } - fn render_stone( - &self, - square_size: i32, - player: Player, - stone: Stone, - row: i32, - col: i32, - shift: i32, - ) { - set_draw_color(match player { - Player::Black => self.black_colour, - Player::White => self.white_colour, - }); + fn render_stone( + &self, + square_size: i32, + player: Player, + stone: Stone, + row: i32, + col: i32, + shift: i32, + ) { + set_draw_color(match player { + Player::Black => self.black_colour, + Player::White => self.white_colour, + }); - // Gap scales with square size - let stone_gap = (square_size as f32 * (1.00 - self.stone_size)).round() as i32; - let d = square_size - stone_gap * 2; - let shift = (shift * d) / 8; - let x1 = self.xorg + col * square_size + stone_gap + shift; - let y1 = self.yorg + row * square_size + stone_gap - shift; + // Gap scales with square size + let stone_gap = (square_size as f32 * (1.00 - self.stone_size)).round() as i32; + let d = square_size - stone_gap * 2; + let shift = (shift * d) / 8; + let x1 = self.xorg + col * square_size + stone_gap + shift; + let y1 = self.yorg + row * square_size + stone_gap - shift; - // Outline with thickness varying by stone size - let setup_border_pen = || { - set_line_style(LineStyle::Solid, i32::max(1, d / 24)); - set_draw_color(Color::Black); - }; + // Outline with thickness varying by stone size + let setup_border_pen = || { + set_line_style(LineStyle::Solid, i32::max(1, d / 24)); + set_draw_color(Color::Black); + }; - match stone { - Stone::Capstone => { - draw_pie(x1, y1, d, d, 0.0, 360.0); - setup_border_pen(); - let r = (d as f64) / 2.0; - draw_circle(r + x1 as f64, r + y1 as f64, r); - } - Stone::Flat => { - draw_rectf(x1, y1, d, d); - setup_border_pen(); - draw_rect_with_color(x1, y1, d, d, Color::Black); - } - Stone::Standing => { - // These look bad shifted so we shift it back if was - let df = d as f64; - // and we have to fudge it a little? Some rounding things presumably - let ds = if shift > 0 { df / 8.0 - 0.5 } else { 0.0 }; - let x1 = x1 as f64 - ds; - let y1 = y1 as f64 + ds; + match stone { + Stone::Capstone => { + draw_pie(x1, y1, d, d, 0.0, 360.0); + setup_border_pen(); + let r = (d as f64) / 2.0; + draw_circle(r + x1 as f64, r + y1 as f64, r); + } + Stone::Flat => { + draw_rectf(x1, y1, d, d); + setup_border_pen(); + draw_rect_with_color(x1, y1, d, d, Color::Black); + } + Stone::Standing => { + // These look bad shifted so we shift it back if was + let df = d as f64; + // and we have to fudge it a little? Some rounding things presumably + let ds = if shift > 0 { df / 8.0 - 0.5 } else { 0.0 }; + let x1 = x1 as f64 - ds; + let y1 = y1 as f64 + ds; - let verts = [ - (x1 + df * 0.3, y1 + df * 0.075), - (x1 + df * 0.925, y1 + df * 0.7), - (x1 + df * 0.7, y1 + df * 0.925), - (x1 + df * 0.075, y1 + df * 0.3), - ]; + let verts = [ + (x1 + df * 0.3, y1 + df * 0.075), + (x1 + df * 0.925, y1 + df * 0.7), + (x1 + df * 0.7, y1 + df * 0.925), + (x1 + df * 0.075, y1 + df * 0.3), + ]; - begin_polygon(); - for (x, y) in verts.iter() { - vertex(*x, *y) - } - end_polygon(); + begin_polygon(); + for (x, y) in verts.iter() { + vertex(*x, *y) + } + end_polygon(); - setup_border_pen(); - begin_loop(); - for (x, y) in verts.iter() { - vertex(*x, *y); - } - end_loop(); - } - } - set_line_style(LineStyle::Solid, 1); - } + setup_border_pen(); + begin_loop(); + for (x, y) in verts.iter() { + vertex(*x, *y); + } + end_loop(); + } + } + set_line_style(LineStyle::Solid, 1); + } - fn render_icons(&self, square_size: i32, player: Player, row: i32, col: i32, shift: i32) { - let stone_gap = square_size as f32 * (1.00 - self.stone_size); - let icon_gap = (stone_gap * 0.15).round() as i32; - let icon_width = (stone_gap * 0.7).round() as i32; - let icon_height = icon_width / 2; + fn render_icons(&self, square_size: i32, player: Player, row: i32, col: i32, shift: i32) { + let stone_gap = square_size as f32 * (1.00 - self.stone_size); + let icon_gap = (stone_gap * 0.15).round() as i32; + let icon_width = (stone_gap * 0.7).round() as i32; + let icon_height = icon_width / 2; - let x1 = self.xorg + col * square_size + icon_gap; - let y1 = self.yorg + (row + 1) * square_size - icon_gap; + let x1 = self.xorg + col * square_size + icon_gap; + let y1 = self.yorg + (row + 1) * square_size - icon_gap; - set_line_style(LineStyle::Solid, i32::max(1, icon_width / 8)); - set_draw_color(Color::Black); + set_line_style(LineStyle::Solid, i32::max(1, icon_width / 8)); + set_draw_color(Color::Black); - set_draw_color(match player { - Player::Black => self.black_colour, - Player::White => self.white_colour, - }); - let y2 = y1 - icon_height * (1 + shift as i32); - draw_rectf(x1, y2, icon_width, icon_height); - draw_rect_with_color(x1, y2, icon_width, icon_height, Color::Black); + set_draw_color(match player { + Player::Black => self.black_colour, + Player::White => self.white_colour, + }); + let y2 = y1 - icon_height * (1 + shift as i32); + draw_rectf(x1, y2, icon_width, icon_height); + draw_rect_with_color(x1, y2, icon_width, icon_height, Color::Black); - set_line_style(LineStyle::Solid, 1); - } + set_line_style(LineStyle::Solid, 1); + } - fn render_stack(&self, square_size: i32, row: i32, col: i32, stack: &Stack) { - // Is there a better way than usize::min((...), i32::MAX as usize) as i32 ? - let cutoff = stack.len() as i32 - self.game_size; + fn render_stack(&self, square_size: i32, row: i32, col: i32, stack: &Stack) { + // Is there a better way than usize::min((...), i32::MAX as usize) as i32 ? + let cutoff = stack.len() as i32 - self.game_size; - for (shift, piece) in stack.iter().enumerate() { - let shift = shift as i32; // TODO: please don't overflow - if shift < cutoff { - self.render_icons(square_size, piece.player, row, col, shift); - } else { - self.render_stone( - square_size, - piece.player, - piece.stone, - row, - col, - shift - i32::max(0, cutoff), - ); - } - } - } + for (shift, piece) in stack.iter().enumerate() { + let shift = shift as i32; // TODO: please don't overflow + if shift < cutoff { + self.render_icons(square_size, piece.player, row, col, shift); + } else { + self.render_stone( + square_size, + piece.player, + piece.stone, + row, + col, + shift - i32::max(0, cutoff), + ); + } + } + } - fn render_board(&self, square_size: i32, board: &Vec<Stack>) { - let mut x = 0; - let mut y = 0; - for stack in board.iter() { - self.render_stack(square_size, x, y, stack); - x += 1; - if x + 1 >= self.game_size { - x = 0; - y += 1; - if y + 1 >= self.game_size { - panic!("Game size mismatch between renderer and internal state."); - } - } - } - } + fn render_board(&self, square_size: i32, board: &Vec<Stack>) { + let mut x = 0; + let mut y = 0; + for stack in board.iter() { + self.render_stack(square_size, x, y, stack); + x += 1; + if x + 1 >= self.game_size { + x = 0; + y += 1; + if y + 1 >= self.game_size { + panic!("Game size mismatch between renderer and internal state."); + } + } + } + } - fn render_background(&self, square_size: i32) { - for x in 0..self.game_size { - for y in 0..self.game_size { - if (x + y) % 2 == 0 { - set_draw_color(self.even_square_colour); - } else { - set_draw_color(self.odd_square_colour); - } - draw_rectf( - self.xorg + x * square_size, - self.yorg + y * square_size, - square_size, - square_size, - ); - } - } - } + fn render_background(&self, square_size: i32) { + for x in 0..self.game_size { + for y in 0..self.game_size { + if (x + y) % 2 == 0 { + set_draw_color(self.even_square_colour); + } else { + set_draw_color(self.odd_square_colour); + } + draw_rectf( + self.xorg + x * square_size, + self.yorg + y * square_size, + square_size, + square_size, + ); + } + } + } } pub struct BoardWidget { - button: Button, - renderer: Rc<BoardRenderer>, + button: Button, + renderer: Rc<BoardRenderer>, } impl BoardWidget { - pub fn new(button: Button, size: i32) -> BoardWidget { - let renderer = Rc::new(BoardRenderer::default().with_size(size).with_org(&button)); - let mut g = BoardWidget { button, renderer }; - g.button.draw2(g.generate_draw(&Vec::new())); - return g; - } + pub fn new(button: Button, size: i32) -> BoardWidget { + let renderer = Rc::new(BoardRenderer::default().with_size(size).with_org(&button)); + let mut g = BoardWidget { button, renderer }; + g.button.draw2(g.generate_draw(&Vec::new())); + return g; + } - pub fn to_square(&self, x: i32, y: i32) -> (i32, i32) { - let square_size = self.renderer.compute_square_size(&self.button); + pub fn to_square(&self, x: i32, y: i32) -> (i32, i32) { + let square_size = self.renderer.compute_square_size(&self.button); - let x = x - self.renderer.xorg; - let y = y - self.renderer.yorg; + let x = x - self.renderer.xorg; + let y = y - self.renderer.yorg; - (x / square_size, y / square_size) - } + (x / square_size, y / square_size) + } - pub fn generate_draw(&self, board: &Vec<Stack>) -> impl FnMut(&mut Button) { - let renderer = self.renderer.clone(); - let board = board.clone(); + pub fn generate_draw(&self, board: &Vec<Stack>) -> impl FnMut(&mut Button) { + let renderer = self.renderer.clone(); + let board = board.clone(); - move |button: &mut Button| { - let square_size = renderer.compute_square_size(&button); - renderer.render_background(square_size); - renderer.render_board(square_size, &board); + move |button: &mut Button| { + let square_size = renderer.compute_square_size(&button); + renderer.render_background(square_size); + renderer.render_board(square_size, &board); - // // Test code for now - // renderer.render_stack(square_size, 1, 4, &stack); - // renderer.render_stone(square_size, Player::Black, Stone::Capstone, 1, 2, 0); - // renderer.render_stone(square_size, Player::Black, Stone::Standing, 2, 2, 0); - } - } + // // Test code for now + // renderer.render_stack(square_size, 1, 4, &stack); + // renderer.render_stone(square_size, Player::Black, Stone::Capstone, 1, 2, 0); + // renderer.render_stone(square_size, Player::Black, Stone::Standing, 2, 2, 0); + } + } } diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 47f56d5..1980fdb 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -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/>. */ mod boardwidget; @@ -22,101 +22,101 @@ use fltk::{app::*, button::*, menu::*, text::*, window::*}; #[derive(Clone, Copy)] enum GUIMessage { - None, - Test, - BoardClick, + None, + Test, + BoardClick, } pub struct GUI { - app: App, - window: DoubleWindow, - board: BoardWidget, - log: TextDisplay, - sender: Sender<GUIMessage>, - receiver: Receiver<GUIMessage>, + app: App, + window: DoubleWindow, + board: BoardWidget, + log: TextDisplay, + sender: Sender<GUIMessage>, + receiver: Receiver<GUIMessage>, } impl GUI { - pub fn new() -> GUI { - let app = App::default(); + pub fn new() -> GUI { + let app = App::default(); - // TODO: Why is this not the same as - /* - let mut window = Window::default() - .with_size(800, 600) - .with_label("Takwrap") - .center_screen(); - */ - // Windows made that way are not resizable? + // TODO: Why is this not the same as + /* + let mut window = Window::default() + .with_size(800, 600) + .with_label("Takwrap") + .center_screen(); + */ + // Windows made that way are not resizable? - let mut window = DoubleWindow::new(0, 0, 800, 600, "Takwrap").center_screen(); + let mut window = DoubleWindow::new(0, 0, 800, 600, "Takwrap").center_screen(); - let (sender, receiver) = channel::<GUIMessage>(); + let (sender, receiver) = channel::<GUIMessage>(); - const MENU_HEIGHT: i32 = 24; - let mut menu = SysMenuBar::default().with_size(800, MENU_HEIGHT); - // menu.set_text_font(Font::Helvetica); - menu.set_color(Color::Light2); - menu.add_emit( - "&File/New...\t", - Shortcut::None, - MenuFlag::Normal, - sender, - GUIMessage::None, - ); - menu.add_emit( - "&File/Open...\t", - Shortcut::None, - MenuFlag::Normal, - sender, - GUIMessage::Test, - ); + const MENU_HEIGHT: i32 = 24; + let mut menu = SysMenuBar::default().with_size(800, MENU_HEIGHT); + // menu.set_text_font(Font::Helvetica); + menu.set_color(Color::Light2); + menu.add_emit( + "&File/New...\t", + Shortcut::None, + MenuFlag::Normal, + sender, + GUIMessage::None, + ); + menu.add_emit( + "&File/Open...\t", + Shortcut::None, + MenuFlag::Normal, + sender, + GUIMessage::Test, + ); - const LOG_WIDTH: i32 = 800 - 600 + MENU_HEIGHT; - let mut log = TextDisplay::default() - .with_size(LOG_WIDTH, 600 - menu.height()) - .with_pos(800 - LOG_WIDTH, menu.height()); - log.set_buffer(Some(TextBuffer::default())); - log.insert("test\n"); + const LOG_WIDTH: i32 = 800 - 600 + MENU_HEIGHT; + let mut log = TextDisplay::default() + .with_size(LOG_WIDTH, 600 - menu.height()) + .with_pos(800 - LOG_WIDTH, menu.height()); + log.set_buffer(Some(TextBuffer::default())); + log.insert("test\n"); - let mut board_button = Button::default() - .with_size(800 - LOG_WIDTH, 600 - menu.height()) - .below_of(&menu, 0); - board_button.set_frame(FrameType::EmbossedBox); - board_button.emit(sender, GUIMessage::BoardClick); + let mut board_button = Button::default() + .with_size(800 - LOG_WIDTH, 600 - menu.height()) + .below_of(&menu, 0); + board_button.set_frame(FrameType::EmbossedBox); + board_button.emit(sender, GUIMessage::BoardClick); - window.resizable(&mut board_button); - window.end(); - window.show(); + window.resizable(&mut board_button); + window.end(); + window.show(); - let board = BoardWidget::new(board_button, 5); + let board = BoardWidget::new(board_button, 5); - // button.emit(sender, GUIMessage::Foo); + // button.emit(sender, GUIMessage::Foo); - GUI { - app, - board, - window, - log, - sender, - receiver, - } - } + GUI { + app, + board, + window, + log, + sender, + receiver, + } + } - pub fn run(&mut self) -> Result<(), fltk::prelude::FltkError> { - while self.app.wait() { - if let Some(msg) = self.receiver.recv() { - match msg { - GUIMessage::BoardClick => { - let x = event_x(); - let y = event_y(); - let (x, y) = self.board.to_square(x, y); - self.log.insert(&format!("Board click ({},{})\n", x, y)); - } - _ => (), - } - } - } - Ok(()) - } + pub fn run(&mut self) -> Result<(), fltk::prelude::FltkError> { + while self.app.wait() { + if let Some(msg) = self.receiver.recv() { + match msg { + GUIMessage::BoardClick => { + let x = event_x(); + let y = event_y(); + let (x, y) = self.board.to_square(x, y); + self.log.insert(&format!("Board click ({},{})\n", x, y)); + } + _ => (), + } + } + } + Ok(()) + } } |
