Start on the NewGame page
This commit is contained in:
parent
6f6579b7a7
commit
ef045117be
|
@ -1,5 +1,5 @@
|
|||
use crate::types::AppState;
|
||||
use crate::ui::{playing_field, PlayingFieldView};
|
||||
use crate::ui::{new_game, playing_field, NewGameView, PlayingFieldView};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use typeshare::typeshare;
|
||||
|
@ -8,8 +8,12 @@ use typeshare::typeshare;
|
|||
#[typeshare]
|
||||
#[serde(tag = "type", content = "content")]
|
||||
pub enum CoreRequest {
|
||||
// CreateGameRequest(CreateGameRequest),
|
||||
LaunchScreen,
|
||||
NewGame,
|
||||
PlayingField,
|
||||
PlayStoneRequest(PlayStoneRequest),
|
||||
StartGame,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
@ -23,6 +27,7 @@ pub struct PlayStoneRequest {
|
|||
#[typeshare]
|
||||
#[serde(tag = "type", content = "content")]
|
||||
pub enum CoreResponse {
|
||||
NewGameView(NewGameView),
|
||||
PlayingFieldView(PlayingFieldView),
|
||||
}
|
||||
|
||||
|
@ -40,6 +45,23 @@ impl CoreApp {
|
|||
|
||||
pub async fn dispatch(&self, request: CoreRequest) -> CoreResponse {
|
||||
match request {
|
||||
/*
|
||||
CoreRequest::LaunchScreen => {
|
||||
let app_state = self.state.read().unwrap();
|
||||
|
||||
At launch, I want to either show a list of games in progress, the current game, or the game creation screen.
|
||||
- if a live game is in progress, immmediately go to that game. Such a game will be classified at game creation, so it should be persisted to the state.
|
||||
- if no live games are in progress, but there are slow games in progress, show a list of the slow games and let the player choose which one to jump into.
|
||||
- if no games are in progress, show only the game creation screen
|
||||
- game creation menu should be present both when there are only slow games and when there are no games
|
||||
- the UI returned here will always be available in other places, such as when the user is viewing a game and wants to return to this page
|
||||
|
||||
For the initial version, I want only to show the game creation screen. Then I will backtrack record application state so that the only decisions can be made.
|
||||
}
|
||||
*/
|
||||
// CoreRequest::LaunchScreen => CoreResponse::NewGameView(new_game()),
|
||||
CoreRequest::LaunchScreen => CoreResponse::NewGameView(new_game()),
|
||||
CoreRequest::NewGame => CoreResponse::NewGameView(new_game()),
|
||||
CoreRequest::PlayingField => {
|
||||
let app_state = self.state.read().unwrap();
|
||||
let game = app_state.game.as_ref().unwrap();
|
||||
|
@ -52,6 +74,9 @@ impl CoreApp {
|
|||
let game = app_state.game.as_ref().unwrap();
|
||||
CoreResponse::PlayingFieldView(playing_field(game))
|
||||
}
|
||||
CoreRequest::StartGame => {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,8 +65,9 @@ impl AppState {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Rank {
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[typeshare]
|
||||
pub enum Rank {
|
||||
Kyu(u8),
|
||||
Dan(u8),
|
||||
Pro(u8),
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
use crate::{
|
||||
ui::types;
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use typeshare::typeshare;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum LaunchScreenView {
|
||||
CreateGame(CreateGameView)
|
||||
}
|
||||
|
||||
// This will be called when the Kifu application starts.
|
||||
pub fn launch_screen() -> LaunchScreenView {
|
||||
}
|
|
@ -1,6 +1,12 @@
|
|||
mod playing_field;
|
||||
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, Menu, NewGameView, Player};
|
||||
|
||||
mod types;
|
||||
pub use types::{
|
||||
BoardElement, ChatElement, IntersectionElement, PlayerCardElement, StoneElement,
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
use crate::types::Rank;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use typeshare::typeshare;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[typeshare]
|
||||
pub struct Menu<T: PartialEq + Eq> {
|
||||
current: Option<T>,
|
||||
options: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Eq> Menu<T> {
|
||||
pub fn new(options: Vec<T>, current: Option<T>) -> Menu<T> {
|
||||
if let Some(ref current) = current {
|
||||
assert!(options.contains(current));
|
||||
}
|
||||
Menu { current, options }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[typeshare]
|
||||
pub enum Player {
|
||||
Hotseat(HotseatPlayer),
|
||||
Remote(RemotePlayer),
|
||||
Bot(BotPlayer),
|
||||
}
|
||||
|
||||
impl Default for Player {
|
||||
fn default() -> Player {
|
||||
Player::Hotseat(HotseatPlayer::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
|
||||
#[typeshare]
|
||||
pub struct HotseatPlayer {
|
||||
pub name: Option<String>,
|
||||
pub rank: Option<Rank>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[typeshare]
|
||||
pub struct RemotePlayer {}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[typeshare]
|
||||
pub struct BotPlayer {}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[typeshare]
|
||||
pub struct NewGameView {
|
||||
pub black_player: Player,
|
||||
pub white_player: Player,
|
||||
}
|
||||
|
||||
pub fn new_game() -> NewGameView {
|
||||
let black_player = Player::Hotseat(HotseatPlayer {
|
||||
name: Some("black_player".to_owned()),
|
||||
..Default::default()
|
||||
});
|
||||
let white_player = Player::Hotseat(HotseatPlayer {
|
||||
name: Some("white_player".to_owned()),
|
||||
..Default::default()
|
||||
});
|
||||
NewGameView {
|
||||
black_player,
|
||||
white_player,
|
||||
}
|
||||
}
|
|
@ -1,8 +1,46 @@
|
|||
use gtk::prelude::*;
|
||||
use kifu_core::{CoreApp, CoreRequest, CoreResponse};
|
||||
use kifu_gtk::{ui::PlayingField, CoreApi};
|
||||
use kifu_gtk::{
|
||||
ui::{NewGame, PlayingField},
|
||||
CoreApi,
|
||||
};
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
fn perftrace<F, A>(trace_name: &str, f: F) -> A
|
||||
where
|
||||
F: FnOnce() -> A,
|
||||
{
|
||||
let start = std::time::Instant::now();
|
||||
let result = f();
|
||||
let end = std::time::Instant::now();
|
||||
println!("[Trace: {}] {:?}", trace_name, end - start);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn handle_response(api: CoreApi, window: gtk::ApplicationWindow, message: CoreResponse) {
|
||||
let playing_field = Arc::new(RwLock::new(None));
|
||||
match message {
|
||||
CoreResponse::NewGameView(view) => {
|
||||
let api = api.clone();
|
||||
|
||||
let new_game = NewGame::new(api, view);
|
||||
window.set_child(Some(&new_game));
|
||||
}
|
||||
CoreResponse::PlayingFieldView(view) => {
|
||||
let api = api.clone();
|
||||
|
||||
let mut playing_field = playing_field.write().unwrap();
|
||||
if playing_field.is_none() {
|
||||
let field = PlayingField::new(api, view);
|
||||
window.set_child(Some(&field));
|
||||
*playing_field = Some(field);
|
||||
} else {
|
||||
playing_field.as_ref().map(|field| field.update_view(view));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
gio::resources_register_include!("com.luminescent-dreams.kifu-gtk.gresource")
|
||||
.expect("Failed to register resources");
|
||||
|
@ -44,30 +82,15 @@ fn main() {
|
|||
|
||||
gtk_rx.attach(None, {
|
||||
let api = api.clone();
|
||||
let playing_field = Arc::new(RwLock::new(None));
|
||||
move |message| {
|
||||
match message {
|
||||
CoreResponse::PlayingFieldView(view) => {
|
||||
let api = api.clone();
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
let mut playing_field = playing_field.write().unwrap();
|
||||
if playing_field.is_none() {
|
||||
let field = PlayingField::new(api, view);
|
||||
window.set_child(Some(&field));
|
||||
*playing_field = Some(field);
|
||||
} else {
|
||||
playing_field.as_ref().map(|field| field.update_view(view));
|
||||
}
|
||||
let end = std::time::Instant::now();
|
||||
println!("Time to render the playing field: {:?}", end - start);
|
||||
}
|
||||
}
|
||||
perftrace("handle_response", || {
|
||||
handle_response(api.clone(), window.clone(), message)
|
||||
});
|
||||
Continue(true)
|
||||
}
|
||||
});
|
||||
|
||||
api.dispatch(CoreRequest::PlayingField);
|
||||
api.dispatch(CoreRequest::NewGame);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -7,6 +7,9 @@ pub use chat::Chat;
|
|||
mod playing_field;
|
||||
pub use playing_field::PlayingField;
|
||||
|
||||
mod new_game;
|
||||
pub use new_game::NewGame;
|
||||
|
||||
mod board;
|
||||
pub use board::Board;
|
||||
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
use crate::CoreApi;
|
||||
use glib::Object;
|
||||
use gtk::{prelude::*, subclass::prelude::*};
|
||||
use kifu_core::ui::{NewGameView, Player};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
pub struct NewGamePrivate {
|
||||
black_player: gtk::Label,
|
||||
white_player: gtk::Label,
|
||||
}
|
||||
|
||||
impl Default for NewGamePrivate {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
black_player: gtk::Label::new(None),
|
||||
white_player: gtk::Label::new(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for NewGamePrivate {
|
||||
const NAME: &'static str = "NewGame";
|
||||
type Type = NewGame;
|
||||
type ParentType = gtk::Grid;
|
||||
}
|
||||
|
||||
impl ObjectImpl for NewGamePrivate {}
|
||||
impl WidgetImpl for NewGamePrivate {}
|
||||
impl GridImpl for NewGamePrivate {}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct NewGame(ObjectSubclass<NewGamePrivate>) @extends gtk::Grid, gtk::Widget;
|
||||
}
|
||||
|
||||
impl NewGame {
|
||||
pub fn new(_api: CoreApi, view: NewGameView) -> NewGame {
|
||||
let s: Self = Object::builder().build();
|
||||
|
||||
match view.black_player {
|
||||
Player::Hotseat(player) => {
|
||||
if let Some(name) = player.name {
|
||||
s.imp().black_player.set_text(name.as_ref());
|
||||
}
|
||||
}
|
||||
Player::Remote(_) => s.imp().black_player.set_text("remote player"),
|
||||
Player::Bot(_) => s.imp().black_player.set_text("bot player"),
|
||||
}
|
||||
s.attach(&s.imp().black_player, 1, 1, 1, 1);
|
||||
|
||||
match view.white_player {
|
||||
Player::Hotseat(player) => {
|
||||
if let Some(name) = player.name {
|
||||
s.imp().white_player.set_text(name.as_ref());
|
||||
}
|
||||
}
|
||||
Player::Remote(_) => s.imp().black_player.set_text("remote player"),
|
||||
Player::Bot(_) => s.imp().black_player.set_text("bot player"),
|
||||
}
|
||||
s.attach(&s.imp().white_player, 2, 1, 1, 1);
|
||||
|
||||
s
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue