use crate::CoreApi; use glib::Object; use gtk::{glib, prelude::*, subclass::prelude::*}; use kifu_core::{ ui::{HomeView, PlayerElement}, CoreRequest, CreateGameRequest, HotseatPlayerRequest, PlayerInfoRequest, }; use std::{cell::RefCell, rc::Rc}; struct PlayerDataEntryPrivate { name: gtk::Text, rank: gtk::DropDown, } impl Default for PlayerDataEntryPrivate { fn default() -> Self { let rank = gtk::DropDown::builder().build(); Self { name: gtk::Text::builder().build(), rank, } } } #[glib::object_subclass] impl ObjectSubclass for PlayerDataEntryPrivate { const NAME: &'static str = "PlayerDataEntry"; type Type = PlayerDataEntry; type ParentType = gtk::Box; } impl ObjectImpl for PlayerDataEntryPrivate {} impl WidgetImpl for PlayerDataEntryPrivate {} impl BoxImpl for PlayerDataEntryPrivate {} glib::wrapper! { struct PlayerDataEntry(ObjectSubclass) @extends gtk::Box, gtk::Widget; } impl PlayerDataEntry { pub fn new(element: PlayerElement) -> PlayerDataEntry { let s: Self = Object::builder().build(); let rank_model = gio::ListStore::new(gtk::StringObject::static_type()); s.imp().rank.set_model(Some(&rank_model)); match element { PlayerElement::Hotseat(player) => { if let Some(placeholder) = player.placeholder { s.imp().name.set_placeholder_text(Some(&placeholder)); } player.ranks.iter().for_each(|rank| rank_model.append(>k::StringObject::new(rank))); } // PlayerElement::Remote(_) => s.imp().placeholder.set_text("remote player"), // PlayerElement::Bot(_) => s.imp().placeholder.set_text("bot player"), } s.append(&s.imp().name); s.append(&s.imp().rank); s } pub fn text(&self) -> String { let name = self.imp().name.buffer().text().to_string(); if name.is_empty() { self.imp() .name .placeholder_text() .map(|s| s.to_string()) .unwrap_or("".to_owned()) } else { name } } pub fn rank(&self) -> Option { self.imp().rank.selected_item().and_then(|obj| { let str_obj = obj.downcast::().ok()?; Some(str_obj.string().clone().to_string()) }) } } pub struct HomePrivate { black_player: Rc>>, white_player: Rc>>, } impl Default for HomePrivate { fn default() -> Self { Self { black_player: Rc::new(RefCell::new(None)), white_player: Rc::new(RefCell::new(None)), } } } #[glib::object_subclass] impl ObjectSubclass for HomePrivate { const NAME: &'static str = "Home"; type Type = Home; type ParentType = gtk::Grid; } impl ObjectImpl for HomePrivate {} impl WidgetImpl for HomePrivate {} impl GridImpl for HomePrivate {} glib::wrapper! { pub struct Home(ObjectSubclass) @extends gtk::Grid, gtk::Widget; } impl Home { pub fn new(api: CoreApi, view: HomeView) -> Home { let s: Self = Object::builder().build(); let black_player = PlayerDataEntry::new(view.black_player); s.attach(&black_player, 1, 1, 1, 1); *s.imp().black_player.borrow_mut() = Some(black_player.clone()); let white_player = PlayerDataEntry::new(view.white_player); s.attach(&white_player, 2, 1, 1, 1); *s.imp().white_player.borrow_mut() = Some(white_player.clone()); let new_game_button = gtk::Button::builder().label(&view.start_game.label).build(); s.attach(&new_game_button, 2, 2, 1, 1); new_game_button.connect_clicked({ move |_| { let black_player = black_player.clone(); let white_player = white_player.clone(); api.dispatch(CoreRequest::CreateGame(CreateGameRequest { black_player: player_info(black_player.clone()), white_player: player_info(white_player.clone()), })); } }); s } } fn player_info(player: PlayerDataEntry) -> PlayerInfoRequest { PlayerInfoRequest::Hotseat(HotseatPlayerRequest { name: player.text(), rank: player.rank(), }) }