Compare commits
3 Commits
a8a9c49f02
...
481226e8c6
Author | SHA1 | Date |
---|---|---|
Savanni D'Gerinel | 481226e8c6 | |
Savanni D'Gerinel | b64eda7efd | |
Savanni D'Gerinel | 553d3f8496 |
|
@ -1,6 +1,6 @@
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum Color {
|
pub enum Color {
|
||||||
Black,
|
Black,
|
||||||
White,
|
White,
|
||||||
|
|
|
@ -2,4 +2,7 @@ mod playing_field;
|
||||||
pub use playing_field::{playing_field, PlayingFieldView};
|
pub use playing_field::{playing_field, PlayingFieldView};
|
||||||
|
|
||||||
mod types;
|
mod types;
|
||||||
pub use types::{ChatElement, GobanElement, PlayerCardElement, StoneElement, TextFieldElement};
|
pub use types::{
|
||||||
|
BoardElement, ChatElement, IntersectionElement, PlayerCardElement, StoneElement,
|
||||||
|
TextFieldElement,
|
||||||
|
};
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::ui::types;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PlayingFieldView {
|
pub struct PlayingFieldView {
|
||||||
pub board: types::GobanElement,
|
pub board: types::BoardElement,
|
||||||
pub player_card_black: types::PlayerCardElement,
|
pub player_card_black: types::PlayerCardElement,
|
||||||
pub player_card_white: types::PlayerCardElement,
|
pub player_card_white: types::PlayerCardElement,
|
||||||
pub chat: types::ChatElement,
|
pub chat: types::ChatElement,
|
||||||
|
@ -12,7 +12,7 @@ pub struct PlayingFieldView {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn playing_field() -> PlayingFieldView {
|
pub fn playing_field() -> PlayingFieldView {
|
||||||
let board = types::GobanElement::default();
|
let board = types::BoardElement::default();
|
||||||
|
|
||||||
let player_card_black = types::PlayerCardElement {
|
let player_card_black = types::PlayerCardElement {
|
||||||
color: Color::Black,
|
color: Color::Black,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use crate::types::{Color, Size};
|
use crate::types::{Color, Size};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub struct Jitter {
|
pub struct Jitter {
|
||||||
pub x: i8,
|
pub x: i8,
|
||||||
pub y: i8,
|
pub y: i8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub struct StoneElement {
|
pub struct StoneElement {
|
||||||
pub color: Color,
|
pub color: Color,
|
||||||
pub jitter: Jitter,
|
pub jitter: Jitter,
|
||||||
|
@ -21,28 +21,44 @@ impl StoneElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct PlayStoneRequest {
|
||||||
|
col: u8,
|
||||||
|
row: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum IntersectionElement {
|
||||||
|
Unplayable,
|
||||||
|
Empty(PlayStoneRequest),
|
||||||
|
Filled(StoneElement),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GobanElement {
|
pub struct BoardElement {
|
||||||
pub size: Size,
|
pub size: Size,
|
||||||
pub spaces: Vec<Option<StoneElement>>,
|
pub spaces: Vec<IntersectionElement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GobanElement {
|
impl BoardElement {
|
||||||
pub fn new(size: Size) -> Self {
|
pub fn new(size: Size) -> Self {
|
||||||
Self {
|
let spaces: Vec<IntersectionElement> = (0..size.height)
|
||||||
size: size.clone(),
|
.map(|row| {
|
||||||
spaces: (0..((size.width as usize) * (size.height as usize)))
|
(0..size.width)
|
||||||
.map(|_| None)
|
.map(|col| IntersectionElement::Empty(PlayStoneRequest { col, row }))
|
||||||
.collect::<Vec<Option<StoneElement>>>(),
|
.collect::<Vec<IntersectionElement>>()
|
||||||
}
|
})
|
||||||
|
.collect::<Vec<Vec<IntersectionElement>>>()
|
||||||
|
.concat();
|
||||||
|
Self { size, spaces }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stone_mut<'a>(&'a mut self, row: u8, col: u8) -> &'a mut Option<StoneElement> {
|
pub fn stone_mut<'a>(&'a mut self, row: u8, col: u8) -> &'a mut IntersectionElement {
|
||||||
let addr = self.addr(row, col);
|
let addr = self.addr(row, col);
|
||||||
&mut self.spaces[addr]
|
&mut self.spaces[addr]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stone(&self, row: u8, col: u8) -> Option<StoneElement> {
|
pub fn stone(&self, row: u8, col: u8) -> IntersectionElement {
|
||||||
self.spaces[self.addr(row, col)].clone()
|
self.spaces[self.addr(row, col)].clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +67,7 @@ impl GobanElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for GobanElement {
|
impl Default for BoardElement {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new(Size::default())
|
Self::new(Size::default())
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,10 @@ use gtk::{
|
||||||
subclass::prelude::*,
|
subclass::prelude::*,
|
||||||
};
|
};
|
||||||
use image::io::Reader as ImageReader;
|
use image::io::Reader as ImageReader;
|
||||||
use kifu_core::{ui::GobanElement, Color};
|
use kifu_core::{
|
||||||
|
ui::{BoardElement, IntersectionElement},
|
||||||
|
Color,
|
||||||
|
};
|
||||||
use std::{cell::RefCell, io::Cursor, rc::Rc};
|
use std::{cell::RefCell, io::Cursor, rc::Rc};
|
||||||
|
|
||||||
const WIDTH: i32 = 800;
|
const WIDTH: i32 = 800;
|
||||||
|
@ -18,36 +21,36 @@ struct Addr {
|
||||||
column: u8,
|
column: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GobanPrivate {
|
pub struct BoardPrivate {
|
||||||
drawing_area: gtk::DrawingArea,
|
drawing_area: gtk::DrawingArea,
|
||||||
|
|
||||||
current_player: Rc<RefCell<Color>>,
|
current_player: Rc<RefCell<Color>>,
|
||||||
goban: Rc<RefCell<GobanElement>>,
|
board: Rc<RefCell<BoardElement>>,
|
||||||
cursor_location: Rc<RefCell<Addr>>,
|
cursor_location: Rc<RefCell<Addr>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
impl ObjectSubclass for GobanPrivate {
|
impl ObjectSubclass for BoardPrivate {
|
||||||
const NAME: &'static str = "Goban";
|
const NAME: &'static str = "Board";
|
||||||
type Type = Goban;
|
type Type = Board;
|
||||||
type ParentType = gtk::Grid;
|
type ParentType = gtk::Grid;
|
||||||
|
|
||||||
fn new() -> GobanPrivate {
|
fn new() -> BoardPrivate {
|
||||||
GobanPrivate {
|
BoardPrivate {
|
||||||
drawing_area: Default::default(),
|
drawing_area: Default::default(),
|
||||||
current_player: Rc::new(RefCell::new(Color::Black)),
|
current_player: Rc::new(RefCell::new(Color::Black)),
|
||||||
goban: Default::default(),
|
board: Default::default(),
|
||||||
cursor_location: Default::default(),
|
cursor_location: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectImpl for GobanPrivate {
|
impl ObjectImpl for BoardPrivate {
|
||||||
fn constructed(&self) {
|
fn constructed(&self) {
|
||||||
self.drawing_area.set_width_request(WIDTH);
|
self.drawing_area.set_width_request(WIDTH);
|
||||||
self.drawing_area.set_height_request(HEIGHT);
|
self.drawing_area.set_height_request(HEIGHT);
|
||||||
|
|
||||||
let goban = self.goban.clone();
|
let board = self.board.clone();
|
||||||
let cursor_location = self.cursor_location.clone();
|
let cursor_location = self.cursor_location.clone();
|
||||||
let current_player = self.current_player.clone();
|
let current_player = self.current_player.clone();
|
||||||
|
|
||||||
|
@ -75,7 +78,7 @@ impl ObjectImpl for GobanPrivate {
|
||||||
|
|
||||||
self.drawing_area
|
self.drawing_area
|
||||||
.set_draw_func(move |_, context, width, height| {
|
.set_draw_func(move |_, context, width, height| {
|
||||||
let goban = goban.borrow();
|
let board = board.borrow();
|
||||||
match background {
|
match background {
|
||||||
Ok(Some(ref background)) => {
|
Ok(Some(ref background)) => {
|
||||||
context.set_source_pixbuf(&background, 0., 0.);
|
context.set_source_pixbuf(&background, 0., 0.);
|
||||||
|
@ -87,8 +90,8 @@ impl ObjectImpl for GobanPrivate {
|
||||||
|
|
||||||
context.set_source_rgb(0.1, 0.1, 0.1);
|
context.set_source_rgb(0.1, 0.1, 0.1);
|
||||||
context.set_line_width(2.);
|
context.set_line_width(2.);
|
||||||
let hspace_between = ((width - 40) as f64) / ((goban.size.width - 1) as f64);
|
let hspace_between = ((width - 40) as f64) / ((board.size.width - 1) as f64);
|
||||||
let vspace_between = ((height - 40) as f64) / ((goban.size.height - 1) as f64);
|
let vspace_between = ((height - 40) as f64) / ((board.size.height - 1) as f64);
|
||||||
|
|
||||||
let pen = Pen {
|
let pen = Pen {
|
||||||
x_offset: 20.,
|
x_offset: 20.,
|
||||||
|
@ -97,12 +100,12 @@ impl ObjectImpl for GobanPrivate {
|
||||||
vspace_between,
|
vspace_between,
|
||||||
};
|
};
|
||||||
|
|
||||||
(0..goban.size.width).for_each(|col| {
|
(0..board.size.width).for_each(|col| {
|
||||||
context.move_to(20.0 + (col as f64) * hspace_between, 20.0);
|
context.move_to(20.0 + (col as f64) * hspace_between, 20.0);
|
||||||
context.line_to(20.0 + (col as f64) * hspace_between, (height as f64) - 20.0);
|
context.line_to(20.0 + (col as f64) * hspace_between, (height as f64) - 20.0);
|
||||||
let _ = context.stroke();
|
let _ = context.stroke();
|
||||||
});
|
});
|
||||||
(0..goban.size.height).for_each(|row| {
|
(0..board.size.height).for_each(|row| {
|
||||||
context.move_to(20.0, 20.0 + (row as f64) * vspace_between);
|
context.move_to(20.0, 20.0 + (row as f64) * vspace_between);
|
||||||
context.line_to((width - 20) as f64, 20.0 + (row as f64) * vspace_between);
|
context.line_to((width - 20) as f64, 20.0 + (row as f64) * vspace_between);
|
||||||
let _ = context.stroke();
|
let _ = context.stroke();
|
||||||
|
@ -117,29 +120,38 @@ impl ObjectImpl for GobanPrivate {
|
||||||
|
|
||||||
(0..19).for_each(|col| {
|
(0..19).for_each(|col| {
|
||||||
(0..19).for_each(|row| {
|
(0..19).for_each(|row| {
|
||||||
match goban.stone(row, col) {
|
match board.stone(row, col) {
|
||||||
None => {}
|
IntersectionElement::Unplayable => {}
|
||||||
Some(element) => {
|
IntersectionElement::Empty(request) => {}
|
||||||
pen.stone(&context, row, col, element.color);
|
IntersectionElement::Filled(stone) => {
|
||||||
|
pen.stone(&context, row, col, stone.color);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let cursor = cursor_location.borrow();
|
let cursor = cursor_location.borrow();
|
||||||
pen.ghost_stone(context, cursor.row, cursor.column, *current_player.borrow());
|
match board.stone(cursor.row, cursor.column) {
|
||||||
|
IntersectionElement::Empty(_) => pen.ghost_stone(
|
||||||
|
context,
|
||||||
|
cursor.row,
|
||||||
|
cursor.column,
|
||||||
|
*current_player.borrow(),
|
||||||
|
),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let motion_controller = gtk::EventControllerMotion::new();
|
let motion_controller = gtk::EventControllerMotion::new();
|
||||||
{
|
{
|
||||||
let goban = self.goban.clone();
|
let board = self.board.clone();
|
||||||
let cursor = self.cursor_location.clone();
|
let cursor = self.cursor_location.clone();
|
||||||
let drawing_area = self.drawing_area.clone();
|
let drawing_area = self.drawing_area.clone();
|
||||||
motion_controller.connect_motion(move |_, x, y| {
|
motion_controller.connect_motion(move |_, x, y| {
|
||||||
let goban = goban.borrow();
|
let board = board.borrow();
|
||||||
let mut cursor = cursor.borrow_mut();
|
let mut cursor = cursor.borrow_mut();
|
||||||
let hspace_between = ((WIDTH - 40) as f64) / ((goban.size.width - 1) as f64);
|
let hspace_between = ((WIDTH - 40) as f64) / ((board.size.width - 1) as f64);
|
||||||
let vspace_between = ((HEIGHT - 40) as f64) / ((goban.size.height - 1) as f64);
|
let vspace_between = ((HEIGHT - 40) as f64) / ((board.size.height - 1) as f64);
|
||||||
|
|
||||||
let addr = Addr {
|
let addr = Addr {
|
||||||
column: ((x.round() - 20.) / hspace_between).round() as u8,
|
column: ((x.round() - 20.) / hspace_between).round() as u8,
|
||||||
|
@ -153,25 +165,42 @@ impl ObjectImpl for GobanPrivate {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let gesture = gtk::GestureClick::new();
|
||||||
|
{
|
||||||
|
let board = self.board.clone();
|
||||||
|
let cursor = self.cursor_location.clone();
|
||||||
|
gesture.connect_released(move |_, _, _, _| {
|
||||||
|
let board = board.borrow();
|
||||||
|
let cursor = cursor.borrow();
|
||||||
|
match board.stone(cursor.row, cursor.column) {
|
||||||
|
IntersectionElement::Empty(request) => {
|
||||||
|
println!("need to send request: {:?}", request)
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
self.drawing_area.add_controller(motion_controller);
|
self.drawing_area.add_controller(motion_controller);
|
||||||
|
self.drawing_area.add_controller(gesture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl WidgetImpl for GobanPrivate {}
|
impl WidgetImpl for BoardPrivate {}
|
||||||
impl GridImpl for GobanPrivate {}
|
impl GridImpl for BoardPrivate {}
|
||||||
|
|
||||||
glib::wrapper! {
|
glib::wrapper! {
|
||||||
pub struct Goban(ObjectSubclass<GobanPrivate>) @extends gtk::Grid, gtk::Widget;
|
pub struct Board(ObjectSubclass<BoardPrivate>) @extends gtk::Grid, gtk::Widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Goban {
|
impl Board {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let s: Self = Object::builder().build();
|
let s: Self = Object::builder().build();
|
||||||
s.attach(&s.imp().drawing_area, 1, 1, 1, 1);
|
s.attach(&s.imp().drawing_area, 1, 1, 1, 1);
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_board(&self, goban: GobanElement) {
|
pub fn set_board(&self, board: BoardElement) {
|
||||||
*self.imp().goban.borrow_mut() = goban;
|
*self.imp().board.borrow_mut() = board;
|
||||||
self.imp().drawing_area.queue_draw();
|
self.imp().drawing_area.queue_draw();
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,8 @@ pub use chat::Chat;
|
||||||
mod playing_field;
|
mod playing_field;
|
||||||
pub use playing_field::PlayingField;
|
pub use playing_field::PlayingField;
|
||||||
|
|
||||||
mod goban;
|
mod board;
|
||||||
pub use goban::Goban;
|
pub use board::Board;
|
||||||
|
|
||||||
#[cfg(feature = "screenplay")]
|
#[cfg(feature = "screenplay")]
|
||||||
pub use playing_field::playing_field_view;
|
pub use playing_field::playing_field_view;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::ui::{Chat, Goban, PlayerCard};
|
use crate::ui::{Board, Chat, PlayerCard};
|
||||||
use glib::Object;
|
use glib::Object;
|
||||||
use gtk::{prelude::*, subclass::prelude::*};
|
use gtk::{prelude::*, subclass::prelude::*};
|
||||||
use kifu_core::{
|
use kifu_core::{
|
||||||
ui::{
|
ui::{
|
||||||
ChatElement, GobanElement, PlayerCardElement, PlayingFieldView, StoneElement,
|
BoardElement, ChatElement, IntersectionElement, PlayerCardElement, PlayingFieldView,
|
||||||
TextFieldElement,
|
StoneElement, TextFieldElement,
|
||||||
},
|
},
|
||||||
Color, Size,
|
Color, Size,
|
||||||
};
|
};
|
||||||
|
@ -23,7 +23,7 @@ pub struct PlayingFieldView {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub struct PlayingFieldPrivate {
|
pub struct PlayingFieldPrivate {
|
||||||
goban: Goban,
|
goban: Board,
|
||||||
player_card_white: Rc<RefCell<Option<PlayerCard>>>,
|
player_card_white: Rc<RefCell<Option<PlayerCard>>>,
|
||||||
player_card_black: Rc<RefCell<Option<PlayerCard>>>,
|
player_card_black: Rc<RefCell<Option<PlayerCard>>>,
|
||||||
chat: Rc<RefCell<Option<Chat>>>,
|
chat: Rc<RefCell<Option<Chat>>>,
|
||||||
|
@ -32,7 +32,7 @@ pub struct PlayingFieldPrivate {
|
||||||
impl Default for PlayingFieldPrivate {
|
impl Default for PlayingFieldPrivate {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
goban: Goban::new(),
|
goban: Board::new(),
|
||||||
player_card_white: Rc::new(RefCell::new(None)),
|
player_card_white: Rc::new(RefCell::new(None)),
|
||||||
player_card_black: Rc::new(RefCell::new(None)),
|
player_card_black: Rc::new(RefCell::new(None)),
|
||||||
chat: Rc::new(RefCell::new(None)),
|
chat: Rc::new(RefCell::new(None)),
|
||||||
|
@ -48,7 +48,7 @@ impl ObjectSubclass for PlayingFieldPrivate {
|
||||||
|
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
goban: Goban::new(),
|
goban: Board::new(),
|
||||||
player_card_white: Rc::new(RefCell::new(None)),
|
player_card_white: Rc::new(RefCell::new(None)),
|
||||||
player_card_black: Rc::new(RefCell::new(None)),
|
player_card_black: Rc::new(RefCell::new(None)),
|
||||||
chat: Rc::new(RefCell::new(None)),
|
chat: Rc::new(RefCell::new(None)),
|
||||||
|
@ -90,9 +90,13 @@ impl PlayingField {
|
||||||
|
|
||||||
#[cfg(feature = "screenplay")]
|
#[cfg(feature = "screenplay")]
|
||||||
pub fn playing_field_view() -> PlayingFieldView {
|
pub fn playing_field_view() -> PlayingFieldView {
|
||||||
let mut board = GobanElement::default();
|
let mut board = BoardElement::new(Size {
|
||||||
*board.stone_mut(4, 4) = Some(StoneElement::new(Color::White));
|
width: 19,
|
||||||
*board.stone_mut(15, 15) = Some(StoneElement::new(Color::Black));
|
height: 19,
|
||||||
|
});
|
||||||
|
*board.stone_mut(4, 4) = IntersectionElement::Filled(StoneElement::new(Color::White));
|
||||||
|
*board.stone_mut(15, 15) = IntersectionElement::Filled(StoneElement::new(Color::Black));
|
||||||
|
*board.stone_mut(18, 18) = IntersectionElement::Unplayable;
|
||||||
let player_card_black = PlayerCardElement {
|
let player_card_black = PlayerCardElement {
|
||||||
color: Color::Black,
|
color: Color::Black,
|
||||||
name: "Savanni".to_owned(),
|
name: "Savanni".to_owned(),
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[toolchain]
|
|
||||||
channel = "1.68.2"
|
|
||||||
components = ["rust-src"]
|
|
Loading…
Reference in New Issue