Compare commits

..

4 Commits

23 changed files with 383 additions and 61 deletions

2
emseries/Cargo.lock generated
View File

@ -71,7 +71,7 @@ dependencies = [
[[package]]
name = "emseries"
version = "0.5.1"
version = "0.6.0"
dependencies = [
"chrono",
"chrono-tz",

85
go-sgf/Cargo.lock generated
View File

@ -51,6 +51,7 @@ dependencies = [
"iana-time-zone",
"js-sys",
"num-traits",
"serde",
"time",
"wasm-bindgen",
"winapi",
@ -68,7 +69,9 @@ version = "0.1.0"
dependencies = [
"chrono",
"nom",
"serde",
"thiserror",
"typeshare",
]
[[package]]
@ -94,6 +97,12 @@ dependencies = [
"cc",
]
[[package]]
name = "itoa"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "js-sys"
version = "0.3.64"
@ -170,6 +179,54 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "ryu"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "serde"
version = "1.0.164"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.164"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.18",
]
[[package]]
name = "serde_json"
version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.18"
@ -198,7 +255,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.18",
]
[[package]]
@ -212,6 +269,28 @@ dependencies = [
"winapi",
]
[[package]]
name = "typeshare"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f44d1a2f454cb35fbe05b218c410792697e76bd868f48d3a418f2cd1a7d527d6"
dependencies = [
"chrono",
"serde",
"serde_json",
"typeshare-annotation",
]
[[package]]
name = "typeshare-annotation"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc670d0e358428857cc3b4bf504c691e572fccaec9542ff09212d3f13d74b7a9"
dependencies = [
"quote",
"syn 1.0.109",
]
[[package]]
name = "unicode-ident"
version = "1.0.9"
@ -245,7 +324,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn",
"syn 2.0.18",
"wasm-bindgen-shared",
]
@ -267,7 +346,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.18",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]

View File

@ -6,6 +6,8 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
chrono = { version = "0.4", features = [ "serde" ] }
nom = { version = "7" }
serde = { version = "1", features = [ "derive" ] }
thiserror = { version = "1"}
chrono = { version = "0.4" }
typeshare = { version = "1" }

View File

@ -1,6 +1,8 @@
use chrono::{Datelike, NaiveDate};
use serde::{Deserialize, Serialize};
use std::num::ParseIntError;
use thiserror::Error;
use typeshare::typeshare;
#[derive(Debug, Error, PartialEq)]
pub enum Error {
@ -14,7 +16,8 @@ pub enum Error {
Unsupported,
}
#[derive(Clone, Debug, PartialEq, PartialOrd)]
#[derive(Clone, Debug, PartialEq, PartialOrd, Deserialize, Serialize)]
#[typeshare]
pub enum Date {
Year(i32),
YearMonth(i32, u32),

View File

@ -72,6 +72,8 @@ use crate::{
date::{self, parse_date_field, Date},
tree::{parse_collection, ParseSizeError, Size},
};
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
#[derive(Debug)]
pub enum Error<'a> {
@ -97,7 +99,8 @@ impl<'a> From<ParseSizeError> for Error<'a> {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[typeshare]
pub enum Rank {
Kyu(u8),
Dan(u8),
@ -118,6 +121,12 @@ impl TryFrom<&str> for Rank {
}
}
impl ToString for Rank {
fn to_string(&self) -> String {
unimplemented!()
}
}
#[derive(Clone, Debug)]
pub struct GameTree {
pub file_format: i8,

View File

@ -1,6 +1,10 @@
pub mod date;
pub mod go;
pub mod tree;
mod date;
pub use date::Date;
mod go;
pub use go::{parse_sgf, GameTree, GameType, Rank};
mod tree;
use thiserror::Error;

3
kifu/core/Cargo.lock generated
View File

@ -45,6 +45,7 @@ dependencies = [
"js-sys",
"num-integer",
"num-traits",
"serde",
"time",
"wasm-bindgen",
"winapi",
@ -125,7 +126,9 @@ version = "0.1.0"
dependencies = [
"chrono",
"nom",
"serde",
"thiserror",
"typeshare",
]
[[package]]

View File

@ -1,7 +1,7 @@
use crate::{
types::{AppState, GameState, Player, Rank},
ui::{new_game, playing_field, NewGameView, PlayingFieldView},
Config,
ui::{home, playing_field, HomeView, PlayingFieldView},
Config, DatabasePath,
};
use serde::{Deserialize, Serialize};
use std::sync::{Arc, RwLock};
@ -12,8 +12,7 @@ use typeshare::typeshare;
#[serde(tag = "type", content = "content")]
pub enum CoreRequest {
CreateGame(CreateGameRequest),
LaunchScreen,
NewGame,
Home,
PlayingField,
PlayStone(PlayStoneRequest),
StartGame,
@ -59,7 +58,7 @@ impl From<HotseatPlayerRequest> for Player {
#[typeshare]
#[serde(tag = "type", content = "content")]
pub enum CoreResponse {
NewGameView(NewGameView),
HomeView(HomeView),
PlayingFieldView(PlayingFieldView),
}
@ -71,8 +70,14 @@ pub struct CoreApp {
impl CoreApp {
pub fn new(config_path: std::path::PathBuf) -> Self {
println!("config_path: {:?}", config_path);
let config = Config::from_path(config_path).expect("configuration to open");
let state = Arc::new(RwLock::new(AppState::new()));
let db_path: DatabasePath = config.get();
let state = Arc::new(RwLock::new(AppState::new(db_path)));
println!("config: {:?}", config);
println!("games database: {:?}", state.read().unwrap().database.len());
Self { config, state }
}
@ -113,8 +118,9 @@ impl CoreApp {
let game_state = app_state.game.as_ref().unwrap();
CoreResponse::PlayingFieldView(playing_field(game_state))
}
CoreRequest::LaunchScreen => CoreResponse::NewGameView(new_game()),
CoreRequest::NewGame => CoreResponse::NewGameView(new_game()),
CoreRequest::Home => {
CoreResponse::HomeView(home(self.state.read().unwrap().database.all_games()))
}
CoreRequest::PlayingField => {
let app_state = self.state.read().unwrap();
let game = app_state.game.as_ref().unwrap();

View File

@ -36,6 +36,7 @@ enum OptionNames {
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ConfigOption {
DatabasePath(DatabasePath),
Me(Me),
@ -96,14 +97,14 @@ impl Config {
}
}
fn set(&mut self, val: ConfigOption) {
pub fn set(&mut self, val: ConfigOption) {
let _ = match val {
ConfigOption::DatabasePath(_) => self.values.insert(OptionNames::DatabasePath, val),
ConfigOption::Me(_) => self.values.insert(OptionNames::Me, val),
};
}
fn get<'a, T>(&'a self) -> T
pub fn get<'a, T>(&'a self) -> T
where
T: From<&'a Self>,
{
@ -111,9 +112,16 @@ impl Config {
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct DatabasePath(PathBuf);
impl std::ops::Deref for DatabasePath {
type Target = PathBuf;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<&Config> for DatabasePath {
fn from(config: &Config) -> Self {
match config.values.get(&OptionNames::DatabasePath) {
@ -123,7 +131,7 @@ impl From<&Config> for DatabasePath {
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Me(Player);
impl From<&Config> for Option<Me> {
@ -137,3 +145,54 @@ impl From<&Config> for Option<Me> {
})
}
}
impl std::ops::Deref for Me {
type Target = Player;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::types::Rank;
use cool_asserts::assert_matches;
#[test]
fn it_can_set_and_get_options() {
let mut config = Config::new(PathBuf::from("."));
config.set(ConfigOption::DatabasePath(DatabasePath(PathBuf::from(
"fixtures/five_games",
))));
config.set(ConfigOption::Me(Me(Player {
name: "Savanni".to_owned(),
rank: Some(Rank::Kyu(10)),
})));
}
#[test]
fn it_can_serialize_and_deserialize() {
let mut config = Config::new(PathBuf::from("."));
config.set(ConfigOption::DatabasePath(DatabasePath(PathBuf::from(
"fixtures/five_games",
))));
config.set(ConfigOption::Me(Me(Player {
name: "Savanni".to_owned(),
rank: Some(Rank::Kyu(10)),
})));
let s = serde_json::to_string(&config.values).unwrap();
println!("{}", s);
let values: HashMap<OptionNames, ConfigOption> = serde_json::from_str(s.as_ref()).unwrap();
println!("options: {:?}", values);
assert_matches!(values.get(&OptionNames::DatabasePath),
Some(ConfigOption::DatabasePath(db_path)) =>
assert_eq!(*db_path, config.get())
);
assert_matches!(values.get(&OptionNames::Me), Some(ConfigOption::Me(val)) =>
assert_eq!(Some(val.clone()), config.get())
);
}
}

View File

@ -1,6 +1,6 @@
use std::{ffi::OsStr, io::Read, os::unix::ffi::OsStrExt, path::PathBuf};
use go_sgf::go::{parse_sgf, GameTree, GameType};
use go_sgf::{parse_sgf, GameTree};
use thiserror::Error;
#[derive(Error, Debug)]
@ -17,6 +17,7 @@ impl From<std::io::Error> for Error {
}
}
#[derive(Debug)]
pub struct Database {
path: PathBuf,
games: Vec<GameTree>,
@ -49,6 +50,10 @@ impl Database {
Ok(Database { path, games })
}
pub fn len(&self) -> usize {
self.games.len()
}
pub fn all_games(&self) -> impl Iterator<Item = &GameTree> {
self.games.iter()
}
@ -58,6 +63,7 @@ impl Database {
mod test {
use super::*;
use cool_asserts::assert_matches;
use go_sgf::{Date, GameType};
#[test]
fn it_reads_empty_database() {
@ -79,7 +85,7 @@ mod test {
Some(game) => {
assert_eq!(game.info.black_player, Some("Steve".to_owned()));
assert_eq!(game.info.white_player, Some("Savanni".to_owned()));
assert_eq!(game.info.date, vec![chrono::NaiveDate::from_ymd_opt(2023, 4, 19).unwrap()]);
assert_eq!(game.info.date, vec![Date::Date(chrono::NaiveDate::from_ymd_opt(2023, 4, 19).unwrap())]);
assert_eq!(game.info.komi, Some(6.5));
}
);

View File

@ -13,4 +13,5 @@ mod database;
mod types;
pub use types::{BoardError, Color, Rank, Size};
pub mod ui;

View File

@ -1,9 +1,11 @@
use crate::{
api::PlayStoneRequest,
board::{Board, Coordinate},
config::DatabasePath,
database::Database,
};
use serde::{Deserialize, Serialize};
use std::time::Duration;
use std::{path::PathBuf, time::Duration};
use thiserror::Error;
use typeshare::typeshare;
@ -43,12 +45,14 @@ impl Default for Size {
#[derive(Debug)]
pub struct AppState {
pub game: Option<GameState>,
pub database: Database,
}
impl AppState {
pub fn new() -> Self {
pub fn new(database_path: DatabasePath) -> Self {
Self {
game: Some(GameState::new()),
database: Database::open_path(database_path.to_path_buf()).unwrap(),
}
}
@ -91,7 +95,7 @@ impl From<Rank> for String {
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Player {
pub name: String,
pub rank: Option<Rank>,

View File

@ -0,0 +1,33 @@
use go_sgf::{Date, GameTree, Rank};
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
#[derive(Clone, Debug, Deserialize, Serialize)]
#[typeshare]
pub struct GamePreviewElement {
pub date: Vec<Date>,
pub black_player: String,
pub black_rank: Option<Rank>,
pub white_player: String,
pub white_rank: Option<Rank>,
}
impl GamePreviewElement {
pub fn new(game: &GameTree) -> GamePreviewElement {
GamePreviewElement {
date: game.info.date.clone(),
black_player: game
.info
.black_player
.clone()
.unwrap_or("black_player".to_owned()),
black_rank: game.info.black_rank.clone(),
white_player: game
.info
.white_player
.clone()
.unwrap_or("white_player".to_owned()),
white_rank: game.info.white_rank.clone(),
}
}
}

View File

@ -1,2 +1,3 @@
pub mod action;
pub mod game_preview;
pub mod menu;

View File

@ -1,4 +1,5 @@
use crate::ui::Action;
use crate::ui::{Action, GamePreviewElement};
use go_sgf::GameTree;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
@ -48,13 +49,14 @@ pub struct BotPlayerElement {}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[typeshare]
pub struct NewGameView {
pub struct HomeView {
pub black_player: PlayerElement,
pub white_player: PlayerElement,
pub games: Vec<GamePreviewElement>,
pub start_game: Action<()>,
}
pub fn new_game() -> NewGameView {
pub fn home<'a>(games: impl Iterator<Item = &'a GameTree>) -> HomeView {
let black_player = PlayerElement::Hotseat(HotseatPlayerElement {
placeholder: Some("black player".to_owned()),
default_rank: None,
@ -65,9 +67,10 @@ pub fn new_game() -> NewGameView {
default_rank: None,
ranks: rank_strings(),
});
NewGameView {
HomeView {
black_player,
white_player,
games: games.map(GamePreviewElement::new).collect(),
start_game: Action {
id: "start-game-action".to_owned(),
label: "New Game".to_owned(),

View File

@ -1,5 +1,5 @@
mod elements;
pub use elements::{action::Action, menu::Menu};
pub use elements::{action::Action, game_preview::GamePreviewElement, menu::Menu};
mod playing_field;
pub use playing_field::{playing_field, PlayingFieldView};
@ -7,8 +7,8 @@ pub use playing_field::{playing_field, PlayingFieldView};
// mod launch_screen;
// pub use launch_screen::{launch_screen, LaunchScreenView};
mod new_game;
pub use new_game::{new_game, HotseatPlayerElement, NewGameView, PlayerElement};
mod home;
pub use home::{home, HomeView, HotseatPlayerElement, PlayerElement};
mod types;
pub use types::{

52
kifu/gtk/Cargo.lock generated
View File

@ -121,6 +121,8 @@ dependencies = [
"js-sys",
"num-integer",
"num-traits",
"serde",
"time",
"wasm-bindgen",
"winapi",
]
@ -442,7 +444,7 @@ dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi",
"wasi 0.11.0+wasi-snapshot-preview1",
"wasm-bindgen",
]
@ -543,6 +545,17 @@ dependencies = [
"system-deps",
]
[[package]]
name = "go-sgf"
version = "0.1.0"
dependencies = [
"chrono",
"nom",
"serde",
"thiserror",
"typeshare",
]
[[package]]
name = "gobject-sys"
version = "0.17.4"
@ -785,6 +798,8 @@ dependencies = [
name = "kifu-core"
version = "0.1.0"
dependencies = [
"chrono",
"go-sgf",
"grid",
"serde",
"serde_json",
@ -862,6 +877,12 @@ dependencies = [
"autocfg",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.6.2"
@ -879,7 +900,7 @@ checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
dependencies = [
"libc",
"log",
"wasi",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys",
]
@ -898,6 +919,16 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "num-integer"
version = "0.1.45"
@ -1330,6 +1361,17 @@ dependencies = [
"weezl",
]
[[package]]
name = "time"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi",
]
[[package]]
name = "tokio"
version = "1.26.0"
@ -1433,6 +1475,12 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"

View File

@ -2,6 +2,7 @@ release:
cargo build --release
dev:
export CONFIG=.
cargo watch -x 'run --bin kifu-gtk'
screenplay:

1
kifu/gtk/config Normal file
View File

@ -0,0 +1 @@
{"Me":{"name":"Savanni","rank":{"Kyu":10}},"DatabasePath":"../core/fixtures/five_games"}

View File

@ -2,7 +2,7 @@ use gtk::prelude::*;
use kifu_core::{CoreApp, CoreRequest, CoreResponse};
use kifu_gtk::{
perftrace,
ui::{NewGame, PlayingField},
ui::{Home, PlayingField},
CoreApi,
};
use std::sync::{Arc, RwLock};
@ -10,10 +10,10 @@ use std::sync::{Arc, RwLock};
fn handle_response(api: CoreApi, window: gtk::ApplicationWindow, message: CoreResponse) {
let playing_field = Arc::new(RwLock::new(None));
match message {
CoreResponse::NewGameView(view) => perftrace("NewGameView", || {
CoreResponse::HomeView(view) => perftrace("HomeView", || {
let api = api.clone();
let new_game = NewGame::new(api, view);
let new_game = Home::new(api, view);
window.set_child(Some(&new_game));
}),
CoreResponse::PlayingFieldView(view) => perftrace("PlayingFieldView", || {
@ -44,10 +44,17 @@ fn main() {
.unwrap(),
);
let user_home = std::env::var("HOME").expect("the user's home directory isn't set");
let mut config_path = std::path::PathBuf::from(user_home);
config_path.push(".config");
config_path.push("kifu");
let config_path = std::env::var("CONFIG")
.and_then(|config| Ok(std::path::PathBuf::from(config)))
.or({
std::env::var("HOME").and_then(|base| {
let mut config_path = std::path::PathBuf::from(base);
config_path.push(".config");
config_path.push("kifu");
Ok(config_path)
})
})
.expect("no config path could be found");
let core = CoreApp::new(config_path);
@ -87,7 +94,7 @@ fn main() {
}
});
api.dispatch(CoreRequest::NewGame);
api.dispatch(CoreRequest::Home);
}
});

View File

@ -0,0 +1,42 @@
use glib::Object;
use gtk::{glib, prelude::*, subclass::prelude::*};
use kifu_core::ui::GamePreviewElement;
#[derive(Default)]
pub struct GamePreviewPrivate;
#[glib::object_subclass]
impl ObjectSubclass for GamePreviewPrivate {
const NAME: &'static str = "GamePreview";
type Type = GamePreview;
type ParentType = gtk::Box;
}
impl ObjectImpl for GamePreviewPrivate {}
impl WidgetImpl for GamePreviewPrivate {}
impl BoxImpl for GamePreviewPrivate {}
glib::wrapper! {
pub struct GamePreview(ObjectSubclass<GamePreviewPrivate>) @extends gtk::Box, gtk::Widget, @implements gtk::Orientable;
}
impl GamePreview {
pub fn new(element: GamePreviewElement) -> GamePreview {
let s: Self = Object::builder().build();
s.set_orientation(gtk::Orientation::Horizontal);
println!("game_preview: {:?}", element);
let black_player = match element.black_rank {
Some(rank) => format!("{} ({})", element.black_player, rank.to_string()),
None => element.black_player,
};
let white_player = match element.white_rank {
Some(rank) => format!("{} ({})", element.white_player, rank.to_string()),
None => element.white_player,
};
s.append(&gtk::Label::new(Some(&black_player)));
s.append(&gtk::Label::new(Some(&white_player)));
s
}
}

View File

@ -1,8 +1,9 @@
use crate::ui::GamePreview;
use crate::CoreApi;
use glib::Object;
use gtk::{glib, prelude::*, subclass::prelude::*};
use kifu_core::{
ui::{NewGameView, PlayerElement},
ui::{HomeView, PlayerElement},
CoreRequest, CreateGameRequest, HotseatPlayerRequest, PlayerInfoRequest,
};
use std::{cell::RefCell, rc::Rc};
@ -82,12 +83,12 @@ impl PlayerDataEntry {
}
}
pub struct NewGamePrivate {
pub struct HomePrivate {
black_player: Rc<RefCell<Option<PlayerDataEntry>>>,
white_player: Rc<RefCell<Option<PlayerDataEntry>>>,
}
impl Default for NewGamePrivate {
impl Default for HomePrivate {
fn default() -> Self {
Self {
black_player: Rc::new(RefCell::new(None)),
@ -97,22 +98,22 @@ impl Default for NewGamePrivate {
}
#[glib::object_subclass]
impl ObjectSubclass for NewGamePrivate {
const NAME: &'static str = "NewGame";
type Type = NewGame;
impl ObjectSubclass for HomePrivate {
const NAME: &'static str = "Home";
type Type = Home;
type ParentType = gtk::Grid;
}
impl ObjectImpl for NewGamePrivate {}
impl WidgetImpl for NewGamePrivate {}
impl GridImpl for NewGamePrivate {}
impl ObjectImpl for HomePrivate {}
impl WidgetImpl for HomePrivate {}
impl GridImpl for HomePrivate {}
glib::wrapper! {
pub struct NewGame(ObjectSubclass<NewGamePrivate>) @extends gtk::Grid, gtk::Widget;
pub struct Home(ObjectSubclass<HomePrivate>) @extends gtk::Grid, gtk::Widget;
}
impl NewGame {
pub fn new(api: CoreApi, view: NewGameView) -> NewGame {
impl Home {
pub fn new(api: CoreApi, view: HomeView) -> Home {
let s: Self = Object::builder().build();
let black_player = PlayerDataEntry::new(view.black_player);
@ -138,6 +139,12 @@ impl NewGame {
}
});
let game_list = gtk::Box::new(gtk::Orientation::Vertical, 0);
s.attach(&game_list, 1, 3, 2, 1);
view.games
.iter()
.for_each(|game_preview| game_list.append(&GamePreview::new(game_preview.clone())));
s
}
}

View File

@ -1,14 +1,17 @@
mod player_card;
pub use player_card::PlayerCard;
mod chat;
pub use chat::Chat;
mod game_preview;
pub use game_preview::GamePreview;
mod player_card;
pub use player_card::PlayerCard;
mod playing_field;
pub use playing_field::PlayingField;
mod new_game;
pub use new_game::NewGame;
mod home;
pub use home::Home;
mod board;
pub use board::Board;