From d929afed2d59b1d69710e5a7897e786e555d5645 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Sat, 23 Mar 2024 14:41:50 -0400 Subject: [PATCH] Start on the new Goban component --- otg/gtk/src/app_window.rs | 4 +- otg/gtk/src/components/goban.rs | 84 +++++++++++++++++++++++++++++++ otg/gtk/src/components/library.rs | 14 +++--- otg/gtk/src/components/mod.rs | 23 ++++++++- otg/gtk/src/views/game_review.rs | 4 +- otg/gtk/src/views/home.rs | 4 +- 6 files changed, 118 insertions(+), 15 deletions(-) create mode 100644 otg/gtk/src/components/goban.rs diff --git a/otg/gtk/src/app_window.rs b/otg/gtk/src/app_window.rs index ec7ae79..6dd60a2 100644 --- a/otg/gtk/src/app_window.rs +++ b/otg/gtk/src/app_window.rs @@ -21,7 +21,7 @@ use otg_core::{ settings::{SettingsRequest, SettingsResponse}, Config, CoreRequest, CoreResponse, }; -use sgf::Game; +use sgf::GameRecord; use std::sync::{Arc, RwLock}; use crate::views::{GameReview, HomeView, SettingsView}; @@ -84,7 +84,7 @@ impl AppWindow { s } - pub fn open_game_review(&self, _game: Game) { + pub fn open_game_review(&self, _game: GameRecord) { let header = adw::HeaderBar::new(); let game_review = GameReview::new(self.core.clone()); diff --git a/otg/gtk/src/components/goban.rs b/otg/gtk/src/components/goban.rs new file mode 100644 index 0000000..c9500ea --- /dev/null +++ b/otg/gtk/src/components/goban.rs @@ -0,0 +1,84 @@ +/* +Copyright 2024, Savanni D'Gerinel + +This file is part of On the Grid. + +On the Grid 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. + +On the Grid 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 On the Grid. If not, see . +*/ + +// I have an old Board class which I'm going to update. I'll just copy over the rendering code, but +// at the same time I am going to work pretty heavily on the API. +// +// For a game review, the board needs to interact very well with a game record. So I have to keep +// in mind all of that as I work on the API. +// +// Also, this is going to be a cross-platform application. Today it is Gnome + Rust, but as I +// progress I will also need a Progressive Web App so that I can run this on my tablet. Especially +// useful if I'm out socializing and happen to be talking to somebody who would enjoy a relaxing +// game. Anyway, that is going to impact some of my API decisions. +// +// First, though, I need to rename my game record. +// +// Now, let's get the existing code compiling again. +// +// Okay, that wasn't so bad. I'm a little confused that I don't have a code action for renaming a +// symbol, but I'll fix that some other time. Anyway, now let's focus on the goban. + + +// Now, we know what kind of object we have for the current board representation. Let's make use of +// that. + +use glib::Object; +use gtk::{prelude::*, subclass::prelude::*}; +use std::{rc::Rc, cell::RefCell}; + +// Internal representation of the Goban drawing area. +#[derive(Default)] +pub struct GobanPrivate { + board_state: Rc>, +} + +#[glib::object_subclass] +impl ObjectSubclass for GobanPrivate { + const NAME: &'static str = "Goban"; + type Type = Goban; + type ParentType = gtk::DrawingArea; +} + +impl ObjectImpl for GobanPrivate {} +impl WidgetImpl for GobanPrivate {} +impl DrawingAreaImpl for GobanPrivate {} + +/// This Goban, being in the `components` crate, is merely the rendering of a board. This is not +/// the primary representation of the board. +/// +/// In a game of Go, there are certain rules about what are valid moves and what are not. +/// Internally, I want to keep track of those, and doing so requires a few things. +/// +/// - We can never repeat a game state (though I think maybe that is allowed in a few rulesets, but +/// I'm coding to the AGA ruleset) +/// - We can never play a suicidal move +/// +/// Finally, updating the board state is non-GUI logic. So, sorry, might be dropping away from GUI +/// code for a while to work on the backend representation, some of which already exists. +glib::wrapper! { + pub struct Goban(ObjectSubclass) @extends gtk::Widget, gtk::DrawingArea; +} + +impl Goban { + pub fn new(board_state: otg_core::Goban) -> Self { + let s: Self = Object::new(); + + *s.imp().board_state.borrow_mut() = board_state; + + s + } +} diff --git a/otg/gtk/src/components/library.rs b/otg/gtk/src/components/library.rs index 81510bb..5d87909 100644 --- a/otg/gtk/src/components/library.rs +++ b/otg/gtk/src/components/library.rs @@ -2,12 +2,12 @@ use adw::{prelude::*, subclass::prelude::*}; use glib::Object; use gtk::glib; // use otg_core::ui::GamePreviewElement; -use sgf::Game; +use sgf::GameRecord; use std::{cell::RefCell, rc::Rc}; #[derive(Default)] pub struct GameObjectPrivate { - game: Rc>>, + game: Rc>>, } #[glib::object_subclass] @@ -23,13 +23,13 @@ glib::wrapper! { } impl GameObject { - pub fn new(game: Game) -> Self { + pub fn new(game: GameRecord) -> Self { let s: Self = Object::builder().build(); *s.imp().game.borrow_mut() = Some(game); s } - pub fn game(&self) -> Option { + pub fn game(&self) -> Option { self.imp().game.borrow().clone() } } @@ -54,7 +54,7 @@ impl Default for LibraryPrivate { fn make_factory(bind: F) -> gtk::SignalListItemFactory where - F: Fn(Game) -> String + 'static, + F: Fn(GameRecord) -> String + 'static, { let factory = gtk::SignalListItemFactory::new(); factory.connect_setup(|_, list_item| { @@ -155,7 +155,7 @@ impl Default for Library { } impl Library { - pub fn new(on_select: impl Fn(Game) + 'static) -> Library { + pub fn new(on_select: impl Fn(GameRecord) + 'static) -> Library { let s = Library::default(); s.imp().list_view.connect_activate({ @@ -177,7 +177,7 @@ impl Library { s } - pub fn set_games(&self, games: Vec) { + pub fn set_games(&self, games: Vec) { let games = games .into_iter() .map(GameObject::new) diff --git a/otg/gtk/src/components/mod.rs b/otg/gtk/src/components/mod.rs index d8fc0be..2cc4847 100644 --- a/otg/gtk/src/components/mod.rs +++ b/otg/gtk/src/components/mod.rs @@ -1,5 +1,21 @@ -mod board; -pub use board::Board; +/* +Copyright 2024, Savanni D'Gerinel + +This file is part of On the Grid. + +On the Grid 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. + +On the Grid 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 On the Grid. If not, see . +*/ + +// mod board; +// pub use board::Board; // mod chat; // pub use chat::Chat; @@ -10,6 +26,9 @@ pub use board::Board; // mod game_preview; // pub use game_preview::GamePreview; +mod goban; +pub use goban::Goban; + mod library; pub use library::Library; diff --git a/otg/gtk/src/views/game_review.rs b/otg/gtk/src/views/game_review.rs index d29e534..d723c52 100644 --- a/otg/gtk/src/views/game_review.rs +++ b/otg/gtk/src/views/game_review.rs @@ -24,7 +24,7 @@ You should have received a copy of the GNU General Public License along with On use glib::Object; use gtk::{prelude::*, subclass::prelude::*}; -use crate::{components::Board, CoreApi}; +use crate::{components::Goban, CoreApi}; pub struct GameReviewPrivate {} @@ -53,7 +53,7 @@ impl GameReview { pub fn new(api: CoreApi) -> Self { let s: Self = Object::builder().build(); - let board = Board::new(api); + let board = Goban::new(otg_core::Goban::default()); s.attach(&board, 0, 0, 2, 2); s.attach(>k::Label::new(Some("white player")), 0, 2, 1, 1); s.attach(>k::Label::new(Some("black player")), 0, 2, 1, 2); diff --git a/otg/gtk/src/views/home.rs b/otg/gtk/src/views/home.rs index 40e5dfc..e8012ef 100644 --- a/otg/gtk/src/views/home.rs +++ b/otg/gtk/src/views/home.rs @@ -21,7 +21,7 @@ use otg_core::{ library::{LibraryRequest, LibraryResponse}, CoreRequest, CoreResponse, }; -use sgf::Game; +use sgf::GameRecord; use std::{cell::RefCell, rc::Rc}; /* @@ -131,7 +131,7 @@ glib::wrapper! { } impl HomeView { - pub fn new(api: CoreApi, on_select_game: impl Fn(Game) + 'static) -> Self { + pub fn new(api: CoreApi, on_select_game: impl Fn(GameRecord) + 'static) -> Self { let s: Self = Object::builder().build(); s.set_spacing(4); s.set_homogeneous(false);