Start on the game review window

This commit is contained in:
Savanni D'Gerinel 2023-08-28 00:44:39 -04:00
parent d6c2a9519b
commit d85d9c4593
10 changed files with 174 additions and 66 deletions

View File

@ -1,6 +1,9 @@
use crate::{ use crate::{
types::{AppState, Config, ConfigOption, DatabasePath, GameState, Player, Rank}, 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 serde::{Deserialize, Serialize};
use std::{ use std::{
@ -17,11 +20,27 @@ pub enum CoreRequest {
CreateGame(CreateGameRequest), CreateGame(CreateGameRequest),
Home, Home,
OpenConfiguration, OpenConfiguration,
OpenGameReview,
PlayingField, PlayingField,
PlayStone(PlayStoneRequest), PlayStone(PlayStoneRequest),
StartGame, 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)] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[typeshare] #[typeshare]
#[serde(tag = "type", content = "content")] #[serde(tag = "type", content = "content")]
@ -65,16 +84,6 @@ impl From<HotseatPlayerRequest> 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)] #[derive(Clone, Debug)]
pub struct CoreApp { pub struct CoreApp {
config: Arc<RwLock<Config>>, config: Arc<RwLock<Config>>,
@ -131,6 +140,7 @@ impl CoreApp {
CoreRequest::OpenConfiguration => { CoreRequest::OpenConfiguration => {
CoreResponse::ConfigurationView(configuration(&self.config.read().unwrap())) CoreResponse::ConfigurationView(configuration(&self.config.read().unwrap()))
} }
CoreRequest::OpenGameReview => CoreResponse::GameReview(review()),
CoreRequest::PlayingField => { CoreRequest::PlayingField => {
let app_state = self.state.read().unwrap(); let app_state = self.state.read().unwrap();
let game = app_state.game.as_ref().unwrap(); let game = app_state.game.as_ref().unwrap();

View File

@ -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<Node>,
}
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![],
}],
}],
},
}
}

View File

@ -4,6 +4,9 @@ pub use configuration::{configuration, ConfigurationView};
mod elements; mod elements;
pub use elements::{game_preview::GamePreviewElement, menu::Menu, Action, Field, Toggle}; pub use elements::{game_preview::GamePreviewElement, menu::Menu, Action, Field, Toggle};
mod game_review;
pub use game_review::{review, GameReviewView};
mod playing_field; mod playing_field;
pub use playing_field::{playing_field, PlayingFieldView}; pub use playing_field::{playing_field, PlayingFieldView};

View File

@ -2,7 +2,7 @@ use adw::prelude::*;
use kifu_core::{CoreApp, CoreRequest, CoreResponse}; use kifu_core::{CoreApp, CoreRequest, CoreResponse};
use kifu_gtk::{ use kifu_gtk::{
perftrace, perftrace,
ui::{AppWindow, ConfigurationPage, Home, PlayingField}, ui::{AppWindow, ConfigurationPage, GameReview, Home, PlayingField},
CoreApi, CoreApi,
}; };
use std::sync::{Arc, RwLock}; 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.set_visible_page(&config_page);
window.present(); window.present();
}), }),
CoreResponse::GameReview(view) => perftrace("GameReview", || {
app_window.set_content(&GameReview::new(api, view));
}),
CoreResponse::HomeView(view) => perftrace("HomeView", || { CoreResponse::HomeView(view) => perftrace("HomeView", || {
let api = api.clone(); let api = api.clone();

View File

@ -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<RefCell<Option<Board>>>,
}
#[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<GameReviewPrivate>)
@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
}
}

View File

@ -137,7 +137,7 @@ impl Home {
.build(); .build();
s.append(&new_game_button); s.append(&new_game_button);
let library = Library::new(); let library = Library::new(api.clone());
let library_view = gtk::ScrolledWindow::builder() let library_view = gtk::ScrolledWindow::builder()
.hscrollbar_policy(gtk::PolicyType::Never) .hscrollbar_policy(gtk::PolicyType::Never)
.min_content_width(360) .min_content_width(360)

View File

@ -1,4 +1,4 @@
use crate::ui::GamePreview; use crate::{ui::GamePreview, CoreApi};
use adw::{prelude::*, subclass::prelude::*}; use adw::{prelude::*, subclass::prelude::*};
use glib::Object; use glib::Object;
use gtk::{glib, prelude::*, subclass::prelude::*}; use gtk::{glib, prelude::*, subclass::prelude::*};
@ -45,38 +45,6 @@ impl Default for LibraryPrivate {
let model = gio::ListStore::new(glib::types::Type::OBJECT); let model = gio::ListStore::new(glib::types::Type::OBJECT);
model.extend_from_slice(&vector); model.extend_from_slice(&vector);
/*
let factory = gtk::SignalListItemFactory::new();
factory.connect_setup(move |_, list_item| {
let preview = GamePreview::new();
list_item
.downcast_ref::<gtk::ListItem>()
.expect("Needs to be a ListItem")
.set_child(Some(&preview));
});
factory.connect_bind(move |_, list_item| {
let game_element = list_item
.downcast_ref::<gtk::ListItem>()
.expect("Needs to be ListItem")
.item()
.and_downcast::<GameObject>()
.expect("The item has to be a GameObject.");
let preview = list_item
.downcast_ref::<gtk::ListItem>()
.expect("Needs to be ListItem")
.child()
.and_downcast::<GamePreview>()
.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 selection_model = gtk::NoSelection::new(Some(model.clone()));
let list_view = gtk::ColumnView::builder().model(&selection_model).build(); let list_view = gtk::ColumnView::builder().model(&selection_model).build();
@ -86,10 +54,10 @@ impl Default for LibraryPrivate {
{ {
let factory = gtk::SignalListItemFactory::new(); let factory = gtk::SignalListItemFactory::new();
factory.connect_setup(|_, list_item| { factory.connect_setup(|_, list_item| {
list_item let item = list_item.downcast_ref::<gtk::ListItem>().unwrap();
.downcast_ref::<gtk::ListItem>()
.unwrap() item.set_activatable(true);
.set_child(Some( item.set_child(Some(
&gtk::Label::builder() &gtk::Label::builder()
.halign(gtk::Align::Start) .halign(gtk::Align::Start)
.ellipsize(pango::EllipsizeMode::End) .ellipsize(pango::EllipsizeMode::End)
@ -149,10 +117,13 @@ glib::wrapper! {
} }
impl Library { impl Library {
pub fn new() -> Self { pub fn new(api: CoreApi) -> Self {
let s: Self = Object::builder().build(); let s: Self = Object::builder().build();
s.set_child(Some(&s.imp().list_view)); 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 s
} }

View File

@ -3,6 +3,9 @@ use gio::resources_lookup_data;
use glib::IsA; use glib::IsA;
use gtk::{prelude::*, STYLE_PROVIDER_PRIORITY_USER}; use gtk::{prelude::*, STYLE_PROVIDER_PRIORITY_USER};
mod board;
pub use board::Board;
mod chat; mod chat;
pub use chat::Chat; pub use chat::Chat;
@ -12,6 +15,12 @@ pub use config::ConfigurationPage;
mod game_preview; mod game_preview;
pub use game_preview::GamePreview; pub use game_preview::GamePreview;
mod game_review;
pub use game_review::GameReview;
mod home;
pub use home::Home;
mod library; mod library;
pub use library::Library; pub use library::Library;
@ -21,11 +30,8 @@ pub use player_card::PlayerCard;
mod playing_field; mod playing_field;
pub use playing_field::PlayingField; pub use playing_field::PlayingField;
mod home; mod review_tree;
pub use home::Home; pub use review_tree::ReviewTree;
mod board;
pub use board::Board;
#[cfg(feature = "screenplay")] #[cfg(feature = "screenplay")]
pub use playing_field::playing_field_view; pub use playing_field::playing_field_view;

View File

@ -12,7 +12,7 @@ pub struct PlayingFieldPrivate {
board: Rc<RefCell<Option<Board>>>, board: Rc<RefCell<Option<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>>>,
} }
impl Default for PlayingFieldPrivate { impl Default for PlayingFieldPrivate {
@ -21,7 +21,7 @@ impl Default for PlayingFieldPrivate {
board: Default::default(), board: Default::default(),
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)),
} }
} }
} }
@ -47,7 +47,7 @@ impl PlayingField {
let player_card_white = PlayerCard::new(view.player_card_white); let player_card_white = PlayerCard::new(view.player_card_white);
let player_card_black = PlayerCard::new(view.player_card_black); 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().board.borrow_mut() = Some(Board::new(api));
s.imp() s.imp()
@ -57,11 +57,11 @@ impl PlayingField {
.map(|board| s.attach(board, 1, 1, 1, 2)); .map(|board| s.attach(board, 1, 1, 1, 2));
s.attach(&player_card_black, 2, 1, 1, 1); s.attach(&player_card_black, 2, 1, 1, 1);
s.attach(&player_card_white, 3, 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_white.borrow_mut() = Some(player_card_white);
*s.imp().player_card_black.borrow_mut() = Some(player_card_black); *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| { s.imp().board.borrow().as_ref().map(|board| {
board.set_board(view.board); board.set_board(view.board);

View File

@ -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<ReviewTreePrivate>)
@extends adw::Bin, gtk::Widget;
}
impl ReviewTree {
pub fn new() -> Self {
let s: Self = Object::builder().build();
s
}
}