From 793cd67218beaf098ee0a38eec4e23ffe2569781 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Wed, 23 Aug 2023 15:57:09 -0400 Subject: [PATCH] Add a header bar and content field for applications --- kifu/core/src/database.rs | 13 +++-- kifu/core/src/ui/elements/game_preview.rs | 1 + kifu/gtk/src/main.rs | 14 ++++-- kifu/gtk/src/ui/game_preview.rs | 2 +- kifu/gtk/src/ui/layout.rs | 61 +++++++++++++++++++++++ kifu/gtk/src/ui/mod.rs | 3 ++ sgf/src/go.rs | 3 +- 7 files changed, 86 insertions(+), 11 deletions(-) create mode 100644 kifu/gtk/src/ui/layout.rs diff --git a/kifu/core/src/database.rs b/kifu/core/src/database.rs index cad6a5c..c7e9cc2 100644 --- a/kifu/core/src/database.rs +++ b/kifu/core/src/database.rs @@ -39,11 +39,16 @@ impl Database { .unwrap() .read_to_string(&mut buffer) .unwrap(); - for sgf in parse_sgf(&buffer).unwrap() { - match sgf { - Game::Go(game) => games.push(game), - Game::Unsupported(_) => {} + match parse_sgf(&buffer) { + Ok(sgfs) => { + for sgf in sgfs { + match sgf { + Game::Go(game) => games.push(game), + Game::Unsupported(_) => {} + } + } } + Err(err) => println!("Error parsing {:?}: {:?}", entry.path(), err), } } } diff --git a/kifu/core/src/ui/elements/game_preview.rs b/kifu/core/src/ui/elements/game_preview.rs index b8660f6..fbd00ea 100644 --- a/kifu/core/src/ui/elements/game_preview.rs +++ b/kifu/core/src/ui/elements/game_preview.rs @@ -50,6 +50,7 @@ impl GamePreviewElement { Some(GameResult::Draw) => "Draw".to_owned(), Some(GameResult::Black(ref win)) => format!("Black by {}", format_win(win)), Some(GameResult::White(ref win)) => format!("White by {}", format_win(win)), + Some(GameResult::Unknown(ref text)) => format!("Unknown: {}", text), None => "".to_owned(), }; diff --git a/kifu/gtk/src/main.rs b/kifu/gtk/src/main.rs index 8423550..f9725e9 100644 --- a/kifu/gtk/src/main.rs +++ b/kifu/gtk/src/main.rs @@ -2,19 +2,19 @@ use adw::prelude::*; use kifu_core::{CoreApp, CoreRequest, CoreResponse}; use kifu_gtk::{ perftrace, - ui::{Home, PlayingField}, + ui::{Home, Layout, PlayingField}, CoreApi, }; use std::sync::{Arc, RwLock}; -fn handle_response(api: CoreApi, window: adw::ApplicationWindow, message: CoreResponse) { +fn handle_response(api: CoreApi, layout: Layout, message: CoreResponse) { let playing_field = Arc::new(RwLock::new(None)); match message { CoreResponse::HomeView(view) => perftrace("HomeView", || { let api = api.clone(); let home = Home::new(api, view); - window.set_content(Some(&home)); + layout.set_content(&home); }), CoreResponse::PlayingFieldView(view) => perftrace("PlayingFieldView", || { let api = api.clone(); @@ -23,7 +23,7 @@ fn handle_response(api: CoreApi, window: adw::ApplicationWindow, message: CoreRe if playing_field.is_none() { perftrace("creating a new playing field", || { let field = PlayingField::new(api, view); - window.set_content(Some(&field)); + layout.set_content(&field); *playing_field = Some(field); }) } else { @@ -101,13 +101,17 @@ fn main() { .width_request(800) .height_request(500) .build(); + + let layout = Layout::new(); + window.set_content(Some(&layout)); + window.present(); gtk_rx.attach(None, { let api = api.clone(); move |message| { perftrace("handle_response", || { - handle_response(api.clone(), window.clone(), message) + handle_response(api.clone(), layout.clone(), message) }); Continue(true) } diff --git a/kifu/gtk/src/ui/game_preview.rs b/kifu/gtk/src/ui/game_preview.rs index feafa96..ff87214 100644 --- a/kifu/gtk/src/ui/game_preview.rs +++ b/kifu/gtk/src/ui/game_preview.rs @@ -31,7 +31,7 @@ impl GamePreview { let s: Self = Object::builder().build(); s.set_orientation(gtk::Orientation::Horizontal); s.set_homogeneous(true); - s.set_hexpand(true); + s.set_hexpand(false); s.append(&s.imp().date); s.append(&s.imp().title); diff --git a/kifu/gtk/src/ui/layout.rs b/kifu/gtk/src/ui/layout.rs new file mode 100644 index 0000000..16cb406 --- /dev/null +++ b/kifu/gtk/src/ui/layout.rs @@ -0,0 +1,61 @@ +use glib::Object; +use gtk::{prelude::*, subclass::prelude::*}; +use std::{cell::RefCell, rc::Rc}; + +// Deprecated even from day 1. We want to use ToolbarView as soon as it's available in the versions +// of Libadwaita available in NixOS. +pub struct LayoutPrivate { + pub header: adw::HeaderBar, + pub content: Rc>, +} + +impl Default for LayoutPrivate { + fn default() -> Self { + let header = adw::HeaderBar::builder() + .title_widget(>k::Label::new(Some("Placeholder Title"))) + .show_start_title_buttons(true) + .show_end_title_buttons(true) + .build(); + let content = adw::StatusPage::builder().title("Nothing here").build(); + + Self { + header, + content: Rc::new(RefCell::new(content.into())), + } + } +} + +#[glib::object_subclass] +impl ObjectSubclass for LayoutPrivate { + const NAME: &'static str = "Layout"; + type Type = Layout; + type ParentType = gtk::Box; +} + +impl ObjectImpl for LayoutPrivate {} +impl WidgetImpl for LayoutPrivate {} +impl BoxImpl for LayoutPrivate {} + +glib::wrapper! { + pub struct Layout(ObjectSubclass) @extends gtk::Box, gtk::Widget, @implements gtk::Orientable; +} + +impl Layout { + pub fn new() -> Self { + let s: Self = Object::builder().build(); + s.set_orientation(gtk::Orientation::Vertical); + s.set_homogeneous(false); + s.append(&s.imp().header); + s.append(&*s.imp().content.borrow()); + + s + } + + pub fn set_content(&self, content: &impl IsA) { + let mut widget = self.imp().content.borrow_mut(); + + self.remove(&*widget); + *widget = content.clone().upcast::(); + self.append(&*widget); + } +} diff --git a/kifu/gtk/src/ui/mod.rs b/kifu/gtk/src/ui/mod.rs index ae70aa6..565384b 100644 --- a/kifu/gtk/src/ui/mod.rs +++ b/kifu/gtk/src/ui/mod.rs @@ -7,6 +7,9 @@ pub use game_preview::GamePreview; mod library; pub use library::Library; +mod layout; +pub use layout::Layout; + mod player_card; pub use player_card::PlayerCard; diff --git a/sgf/src/go.rs b/sgf/src/go.rs index 283ba2d..0fc3db0 100644 --- a/sgf/src/go.rs +++ b/sgf/src/go.rs @@ -242,6 +242,7 @@ pub enum GameResult { Draw, Black(Win), White(Win), + Unknown(String), } impl TryFrom<&str> for GameResult { @@ -256,7 +257,7 @@ impl TryFrom<&str> for GameResult { let res = match parts[0].to_ascii_lowercase().as_str() { "b" => GameResult::Black, "w" => GameResult::White, - _ => panic!("unknown result format"), + _ => return Ok(GameResult::Unknown(parts[0].to_owned())), }; match parts[1].to_ascii_lowercase().as_str() { "r" | "resign" => Ok(res(Win::Resignation)),