Add a header bar and content field for applications
This commit is contained in:
parent
ff13ff3c0e
commit
793cd67218
|
@ -39,11 +39,16 @@ 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) {
|
||||||
match sgf {
|
Ok(sgfs) => {
|
||||||
Game::Go(game) => games.push(game),
|
for sgf in sgfs {
|
||||||
Game::Unsupported(_) => {}
|
match sgf {
|
||||||
|
Game::Go(game) => games.push(game),
|
||||||
|
Game::Unsupported(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Err(err) => println!("Error parsing {:?}: {:?}", entry.path(), err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(>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<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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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)),
|
||||||
|
|
Loading…
Reference in New Issue