From d85d9c4593877d2a0abb07256709d2f0c63cea42 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Mon, 28 Aug 2023 00:44:39 -0400 Subject: [PATCH] Start on the game review window --- kifu/core/src/api.rs | 32 ++++++++++++------ kifu/core/src/ui/game_review.rs | 50 ++++++++++++++++++++++++++++ kifu/core/src/ui/mod.rs | 3 ++ kifu/gtk/src/main.rs | 5 ++- kifu/gtk/src/ui/game_review.rs | 35 ++++++++++++++++++++ kifu/gtk/src/ui/home.rs | 2 +- kifu/gtk/src/ui/library.rs | 57 ++++++++------------------------ kifu/gtk/src/ui/mod.rs | 16 ++++++--- kifu/gtk/src/ui/playing_field.rs | 10 +++--- kifu/gtk/src/ui/review_tree.rs | 30 +++++++++++++++++ 10 files changed, 174 insertions(+), 66 deletions(-) create mode 100644 kifu/core/src/ui/game_review.rs create mode 100644 kifu/gtk/src/ui/game_review.rs create mode 100644 kifu/gtk/src/ui/review_tree.rs diff --git a/kifu/core/src/api.rs b/kifu/core/src/api.rs index 76d5264..0c47e67 100644 --- a/kifu/core/src/api.rs +++ b/kifu/core/src/api.rs @@ -1,6 +1,9 @@ use crate::{ types::{AppState, Config, ConfigOption, DatabasePath, GameState, Player, Rank}, - ui::{configuration, home, playing_field, ConfigurationView, HomeView, PlayingFieldView}, + ui::{ + configuration, home, playing_field, review, ConfigurationView, GameReviewView, HomeView, + PlayingFieldView, + }, }; use serde::{Deserialize, Serialize}; use std::{ @@ -17,11 +20,27 @@ pub enum CoreRequest { CreateGame(CreateGameRequest), Home, OpenConfiguration, + OpenGameReview, PlayingField, PlayStone(PlayStoneRequest), StartGame, } +#[derive(Clone, Debug, Serialize, Deserialize)] +#[typeshare] +#[serde(tag = "type", content = "content")] +pub enum CoreResponse { + ConfigurationView(ConfigurationView), + HomeView(HomeView), + GameReview(GameReviewView), + PlayingFieldView(PlayingFieldView), + UpdatedConfigurationView(ConfigurationView), +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[typeshare] +pub struct GameId(String); + #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[typeshare] #[serde(tag = "type", content = "content")] @@ -65,16 +84,6 @@ impl From for Player { } } -#[derive(Clone, Debug, Serialize, Deserialize)] -#[typeshare] -#[serde(tag = "type", content = "content")] -pub enum CoreResponse { - ConfigurationView(ConfigurationView), - HomeView(HomeView), - PlayingFieldView(PlayingFieldView), - UpdatedConfigurationView(ConfigurationView), -} - #[derive(Clone, Debug)] pub struct CoreApp { config: Arc>, @@ -131,6 +140,7 @@ impl CoreApp { CoreRequest::OpenConfiguration => { CoreResponse::ConfigurationView(configuration(&self.config.read().unwrap())) } + CoreRequest::OpenGameReview => CoreResponse::GameReview(review()), CoreRequest::PlayingField => { let app_state = self.state.read().unwrap(); let game = app_state.game.as_ref().unwrap(); diff --git a/kifu/core/src/ui/game_review.rs b/kifu/core/src/ui/game_review.rs new file mode 100644 index 0000000..e695227 --- /dev/null +++ b/kifu/core/src/ui/game_review.rs @@ -0,0 +1,50 @@ +use crate::Color; +use serde::{Deserialize, Serialize}; +use sgf::go::Game; +use typeshare::typeshare; + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[typeshare] +pub struct GameReviewView { + pub black_player: String, + pub white_player: String, + pub tree: Node, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[typeshare] +pub struct Position { + pub column: u8, + pub row: u8, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[typeshare] +pub struct Node { + pub color: Color, + pub position: Position, + pub children: Vec, +} + +pub fn review() -> GameReviewView { + GameReviewView { + black_player: "savanni".to_owned(), + white_player: "kat".to_owned(), + tree: Node { + color: Color::Black, + position: Position { column: 3, row: 3 }, + children: vec![Node { + color: Color::White, + position: Position { + column: 15, + row: 15, + }, + children: vec![Node { + color: Color::Black, + position: Position { column: 15, row: 3 }, + children: vec![], + }], + }], + }, + } +} diff --git a/kifu/core/src/ui/mod.rs b/kifu/core/src/ui/mod.rs index 9c63d14..a662877 100644 --- a/kifu/core/src/ui/mod.rs +++ b/kifu/core/src/ui/mod.rs @@ -4,6 +4,9 @@ pub use configuration::{configuration, ConfigurationView}; mod elements; pub use elements::{game_preview::GamePreviewElement, menu::Menu, Action, Field, Toggle}; +mod game_review; +pub use game_review::{review, GameReviewView}; + mod playing_field; pub use playing_field::{playing_field, PlayingFieldView}; diff --git a/kifu/gtk/src/main.rs b/kifu/gtk/src/main.rs index 614b1dc..a5c66f9 100644 --- a/kifu/gtk/src/main.rs +++ b/kifu/gtk/src/main.rs @@ -2,7 +2,7 @@ use adw::prelude::*; use kifu_core::{CoreApp, CoreRequest, CoreResponse}; use kifu_gtk::{ perftrace, - ui::{AppWindow, ConfigurationPage, Home, PlayingField}, + ui::{AppWindow, ConfigurationPage, GameReview, Home, PlayingField}, CoreApi, }; use std::sync::{Arc, RwLock}; @@ -18,6 +18,9 @@ fn handle_response(api: CoreApi, app_window: &AppWindow, message: CoreResponse) window.set_visible_page(&config_page); window.present(); }), + CoreResponse::GameReview(view) => perftrace("GameReview", || { + app_window.set_content(&GameReview::new(api, view)); + }), CoreResponse::HomeView(view) => perftrace("HomeView", || { let api = api.clone(); diff --git a/kifu/gtk/src/ui/game_review.rs b/kifu/gtk/src/ui/game_review.rs new file mode 100644 index 0000000..a9d22ba --- /dev/null +++ b/kifu/gtk/src/ui/game_review.rs @@ -0,0 +1,35 @@ +use crate::{ui::Board, CoreApi}; +use glib::Object; +use gtk::{prelude::*, subclass::prelude::*}; +use kifu_core::ui::GameReviewView; +use std::{cell::RefCell, rc::Rc}; + +#[derive(Default)] +pub struct GameReviewPrivate { + board: Rc>>, +} + +#[glib::object_subclass] +impl ObjectSubclass for GameReviewPrivate { + const NAME: &'static str = "GameReview"; + type Type = GameReview; + type ParentType = gtk::Box; +} + +impl ObjectImpl for GameReviewPrivate {} +impl WidgetImpl for GameReviewPrivate {} +impl BoxImpl for GameReviewPrivate {} + +glib::wrapper! { + pub struct GameReview(ObjectSubclass) + @extends gtk::Box, gtk::Widget, + @implements gtk::Orientable; +} + +impl GameReview { + pub fn new(api: CoreApi, view: GameReviewView) -> Self { + let s: Self = Object::builder().build(); + + s + } +} diff --git a/kifu/gtk/src/ui/home.rs b/kifu/gtk/src/ui/home.rs index daf0691..07f2910 100644 --- a/kifu/gtk/src/ui/home.rs +++ b/kifu/gtk/src/ui/home.rs @@ -137,7 +137,7 @@ impl Home { .build(); s.append(&new_game_button); - let library = Library::new(); + let library = Library::new(api.clone()); let library_view = gtk::ScrolledWindow::builder() .hscrollbar_policy(gtk::PolicyType::Never) .min_content_width(360) diff --git a/kifu/gtk/src/ui/library.rs b/kifu/gtk/src/ui/library.rs index a2b42c6..1f32ee8 100644 --- a/kifu/gtk/src/ui/library.rs +++ b/kifu/gtk/src/ui/library.rs @@ -1,4 +1,4 @@ -use crate::ui::GamePreview; +use crate::{ui::GamePreview, CoreApi}; use adw::{prelude::*, subclass::prelude::*}; use glib::Object; use gtk::{glib, prelude::*, subclass::prelude::*}; @@ -45,38 +45,6 @@ impl Default for LibraryPrivate { let model = gio::ListStore::new(glib::types::Type::OBJECT); model.extend_from_slice(&vector); - /* - let factory = gtk::SignalListItemFactory::new(); - - factory.connect_setup(move |_, list_item| { - let preview = GamePreview::new(); - list_item - .downcast_ref::() - .expect("Needs to be a ListItem") - .set_child(Some(&preview)); - }); - factory.connect_bind(move |_, list_item| { - let game_element = list_item - .downcast_ref::() - .expect("Needs to be ListItem") - .item() - .and_downcast::() - .expect("The item has to be a GameObject."); - - let preview = list_item - .downcast_ref::() - .expect("Needs to be ListItem") - .child() - .and_downcast::() - .expect("The child has to be a GamePreview object."); - - match game_element.game() { - Some(game) => preview.set_game(game), - None => (), - }; - }); - */ - let selection_model = gtk::NoSelection::new(Some(model.clone())); let list_view = gtk::ColumnView::builder().model(&selection_model).build(); @@ -86,15 +54,15 @@ impl Default for LibraryPrivate { { let factory = gtk::SignalListItemFactory::new(); factory.connect_setup(|_, list_item| { - list_item - .downcast_ref::() - .unwrap() - .set_child(Some( - >k::Label::builder() - .halign(gtk::Align::Start) - .ellipsize(pango::EllipsizeMode::End) - .build(), - )) + let item = list_item.downcast_ref::().unwrap(); + + item.set_activatable(true); + item.set_child(Some( + >k::Label::builder() + .halign(gtk::Align::Start) + .ellipsize(pango::EllipsizeMode::End) + .build(), + )) }); factory.connect_bind(move |_, list_item| { let list_item = list_item.downcast_ref::().unwrap(); @@ -149,10 +117,13 @@ glib::wrapper! { } impl Library { - pub fn new() -> Self { + pub fn new(api: CoreApi) -> Self { let s: Self = Object::builder().build(); s.set_child(Some(&s.imp().list_view)); + s.imp().list_view.connect_activate(move |list, row_id| { + api.dispatch(kifu_core::CoreRequest::OpenGameReview); + }); s } diff --git a/kifu/gtk/src/ui/mod.rs b/kifu/gtk/src/ui/mod.rs index 5b5bfcd..97d2ad8 100644 --- a/kifu/gtk/src/ui/mod.rs +++ b/kifu/gtk/src/ui/mod.rs @@ -3,6 +3,9 @@ use gio::resources_lookup_data; use glib::IsA; use gtk::{prelude::*, STYLE_PROVIDER_PRIORITY_USER}; +mod board; +pub use board::Board; + mod chat; pub use chat::Chat; @@ -12,6 +15,12 @@ pub use config::ConfigurationPage; mod game_preview; pub use game_preview::GamePreview; +mod game_review; +pub use game_review::GameReview; + +mod home; +pub use home::Home; + mod library; pub use library::Library; @@ -21,11 +30,8 @@ pub use player_card::PlayerCard; mod playing_field; pub use playing_field::PlayingField; -mod home; -pub use home::Home; - -mod board; -pub use board::Board; +mod review_tree; +pub use review_tree::ReviewTree; #[cfg(feature = "screenplay")] pub use playing_field::playing_field_view; diff --git a/kifu/gtk/src/ui/playing_field.rs b/kifu/gtk/src/ui/playing_field.rs index dce713e..8b141a6 100644 --- a/kifu/gtk/src/ui/playing_field.rs +++ b/kifu/gtk/src/ui/playing_field.rs @@ -12,7 +12,7 @@ pub struct PlayingFieldPrivate { board: Rc>>, player_card_white: Rc>>, player_card_black: Rc>>, - chat: Rc>>, + // chat: Rc>>, } impl Default for PlayingFieldPrivate { @@ -21,7 +21,7 @@ impl Default for PlayingFieldPrivate { board: Default::default(), player_card_white: 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)), } } } @@ -47,7 +47,7 @@ impl PlayingField { let player_card_white = PlayerCard::new(view.player_card_white); let player_card_black = PlayerCard::new(view.player_card_black); - let chat = Chat::new(view.chat); + // let chat = Chat::new(view.chat); *s.imp().board.borrow_mut() = Some(Board::new(api)); s.imp() @@ -57,11 +57,11 @@ impl PlayingField { .map(|board| s.attach(board, 1, 1, 1, 2)); s.attach(&player_card_black, 2, 1, 1, 1); s.attach(&player_card_white, 3, 1, 1, 1); - s.attach(&chat, 2, 2, 2, 1); + // s.attach(&chat, 2, 2, 2, 1); *s.imp().player_card_white.borrow_mut() = Some(player_card_white); *s.imp().player_card_black.borrow_mut() = Some(player_card_black); - *s.imp().chat.borrow_mut() = Some(chat); + // *s.imp().chat.borrow_mut() = Some(chat); s.imp().board.borrow().as_ref().map(|board| { board.set_board(view.board); diff --git a/kifu/gtk/src/ui/review_tree.rs b/kifu/gtk/src/ui/review_tree.rs new file mode 100644 index 0000000..21fc55b --- /dev/null +++ b/kifu/gtk/src/ui/review_tree.rs @@ -0,0 +1,30 @@ +use adw::{prelude::*, subclass::prelude::*}; +use glib::Object; +use std::{cell::Cell, rc::Rc}; + +#[derive(Default)] +pub struct ReviewTreePrivate {} + +#[glib::object_subclass] +impl ObjectSubclass for ReviewTreePrivate { + const NAME: &'static str = "ReviewTree"; + type Type = ReviewTree; + type ParentType = adw::Bin; +} + +impl ObjectImpl for ReviewTreePrivate {} +impl WidgetImpl for ReviewTreePrivate {} +impl BinImpl for ReviewTreePrivate {} + +glib::wrapper! { + pub struct ReviewTree(ObjectSubclass) + @extends adw::Bin, gtk::Widget; +} + +impl ReviewTree { + pub fn new() -> Self { + let s: Self = Object::builder().build(); + + s + } +}