Add a header bar and content field for applications

This commit is contained in:
Savanni D'Gerinel 2023-08-23 15:57:09 -04:00
parent ff13ff3c0e
commit 793cd67218
7 changed files with 86 additions and 11 deletions

View File

@ -39,13 +39,18 @@ impl Database {
.unwrap() .unwrap()
.read_to_string(&mut buffer) .read_to_string(&mut buffer)
.unwrap(); .unwrap();
for sgf in parse_sgf(&buffer).unwrap() { match parse_sgf(&buffer) {
Ok(sgfs) => {
for sgf in sgfs {
match sgf { match sgf {
Game::Go(game) => games.push(game), Game::Go(game) => games.push(game),
Game::Unsupported(_) => {} Game::Unsupported(_) => {}
} }
} }
} }
Err(err) => println!("Error parsing {:?}: {:?}", entry.path(), err),
}
}
} }
Err(err) => println!("failed entry: {:?}", err), Err(err) => println!("failed entry: {:?}", err),
} }

View File

@ -50,6 +50,7 @@ impl GamePreviewElement {
Some(GameResult::Draw) => "Draw".to_owned(), Some(GameResult::Draw) => "Draw".to_owned(),
Some(GameResult::Black(ref win)) => format!("Black by {}", format_win(win)), Some(GameResult::Black(ref win)) => format!("Black by {}", format_win(win)),
Some(GameResult::White(ref win)) => format!("White 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(), None => "".to_owned(),
}; };

View File

@ -2,19 +2,19 @@ use adw::prelude::*;
use kifu_core::{CoreApp, CoreRequest, CoreResponse}; use kifu_core::{CoreApp, CoreRequest, CoreResponse};
use kifu_gtk::{ use kifu_gtk::{
perftrace, perftrace,
ui::{Home, PlayingField}, ui::{Home, Layout, PlayingField},
CoreApi, CoreApi,
}; };
use std::sync::{Arc, RwLock}; 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)); let playing_field = Arc::new(RwLock::new(None));
match message { match message {
CoreResponse::HomeView(view) => perftrace("HomeView", || { CoreResponse::HomeView(view) => perftrace("HomeView", || {
let api = api.clone(); let api = api.clone();
let home = Home::new(api, view); let home = Home::new(api, view);
window.set_content(Some(&home)); layout.set_content(&home);
}), }),
CoreResponse::PlayingFieldView(view) => perftrace("PlayingFieldView", || { CoreResponse::PlayingFieldView(view) => perftrace("PlayingFieldView", || {
let api = api.clone(); let api = api.clone();
@ -23,7 +23,7 @@ fn handle_response(api: CoreApi, window: adw::ApplicationWindow, message: CoreRe
if playing_field.is_none() { if playing_field.is_none() {
perftrace("creating a new playing field", || { perftrace("creating a new playing field", || {
let field = PlayingField::new(api, view); let field = PlayingField::new(api, view);
window.set_content(Some(&field)); layout.set_content(&field);
*playing_field = Some(field); *playing_field = Some(field);
}) })
} else { } else {
@ -101,13 +101,17 @@ fn main() {
.width_request(800) .width_request(800)
.height_request(500) .height_request(500)
.build(); .build();
let layout = Layout::new();
window.set_content(Some(&layout));
window.present(); window.present();
gtk_rx.attach(None, { gtk_rx.attach(None, {
let api = api.clone(); let api = api.clone();
move |message| { move |message| {
perftrace("handle_response", || { perftrace("handle_response", || {
handle_response(api.clone(), window.clone(), message) handle_response(api.clone(), layout.clone(), message)
}); });
Continue(true) Continue(true)
} }

View File

@ -31,7 +31,7 @@ impl GamePreview {
let s: Self = Object::builder().build(); let s: Self = Object::builder().build();
s.set_orientation(gtk::Orientation::Horizontal); s.set_orientation(gtk::Orientation::Horizontal);
s.set_homogeneous(true); s.set_homogeneous(true);
s.set_hexpand(true); s.set_hexpand(false);
s.append(&s.imp().date); s.append(&s.imp().date);
s.append(&s.imp().title); s.append(&s.imp().title);

61
kifu/gtk/src/ui/layout.rs Normal file
View File

@ -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<RefCell<gtk::Widget>>,
}
impl Default for LayoutPrivate {
fn default() -> Self {
let header = adw::HeaderBar::builder()
.title_widget(&gtk::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<LayoutPrivate>) @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<gtk::Widget>) {
let mut widget = self.imp().content.borrow_mut();
self.remove(&*widget);
*widget = content.clone().upcast::<gtk::Widget>();
self.append(&*widget);
}
}

View File

@ -7,6 +7,9 @@ pub use game_preview::GamePreview;
mod library; mod library;
pub use library::Library; pub use library::Library;
mod layout;
pub use layout::Layout;
mod player_card; mod player_card;
pub use player_card::PlayerCard; pub use player_card::PlayerCard;

View File

@ -242,6 +242,7 @@ pub enum GameResult {
Draw, Draw,
Black(Win), Black(Win),
White(Win), White(Win),
Unknown(String),
} }
impl TryFrom<&str> for GameResult { impl TryFrom<&str> for GameResult {
@ -256,7 +257,7 @@ impl TryFrom<&str> for GameResult {
let res = match parts[0].to_ascii_lowercase().as_str() { let res = match parts[0].to_ascii_lowercase().as_str() {
"b" => GameResult::Black, "b" => GameResult::Black,
"w" => GameResult::White, "w" => GameResult::White,
_ => panic!("unknown result format"), _ => return Ok(GameResult::Unknown(parts[0].to_owned())),
}; };
match parts[1].to_ascii_lowercase().as_str() { match parts[1].to_ascii_lowercase().as_str() {
"r" | "resign" => Ok(res(Win::Resignation)), "r" | "resign" => Ok(res(Win::Resignation)),