diff --git a/Cargo.lock b/Cargo.lock
index 1967a17..d933eae 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
[[package]]
name = "addr2line"
-version = "0.20.0"
+version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3"
+checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
dependencies = [
"gimli",
]
@@ -55,9 +55,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "backtrace"
-version = "0.3.68"
+version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12"
+checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
dependencies = [
"addr2line",
"cc",
@@ -158,9 +158,9 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.0.82"
+version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01"
+checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
@@ -427,9 +427,9 @@ dependencies = [
[[package]]
name = "encoding_rs"
-version = "0.8.32"
+version = "0.8.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
+checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
dependencies = [
"cfg-if",
]
@@ -803,9 +803,9 @@ dependencies = [
[[package]]
name = "gimli"
-version = "0.27.3"
+version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
+checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
[[package]]
name = "gio"
@@ -1051,9 +1051,9 @@ dependencies = [
[[package]]
name = "h2"
-version = "0.3.20"
+version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049"
+checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833"
dependencies = [
"bytes",
"fnv",
@@ -1349,6 +1349,7 @@ dependencies = [
"image",
"kifu-core",
"libadwaita",
+ "pango",
"sgf",
"tokio",
]
@@ -1577,9 +1578,9 @@ dependencies = [
[[package]]
name = "object"
-version = "0.31.1"
+version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
+checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe"
dependencies = [
"memchr",
]
@@ -1987,9 +1988,9 @@ checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
[[package]]
name = "reqwest"
-version = "0.11.18"
+version = "0.11.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55"
+checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1"
dependencies = [
"base64",
"bytes",
@@ -2133,18 +2134,18 @@ checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
[[package]]
name = "serde"
-version = "1.0.183"
+version = "1.0.186"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c"
+checksum = "9f5db24220c009de9bd45e69fb2938f4b6d2df856aa9304ce377b3180f83b7c1"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.183"
+version = "1.0.186"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816"
+checksum = "5ad697f7e0b65af4983a4ce8f56ed5b357e8d3c36651bf6a7e13639c17b8e670"
dependencies = [
"proc-macro2",
"quote",
@@ -2211,15 +2212,15 @@ checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]]
name = "siphasher"
-version = "0.3.10"
+version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
+checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
[[package]]
name = "slab"
-version = "0.4.8"
+version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
"autocfg",
]
@@ -2840,20 +2841,21 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "winnow"
-version = "0.5.14"
+version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d09770118a7eb1ccaf4a594a221334119a44a814fcb0d31c5b85e83e97227a97"
+checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc"
dependencies = [
"memchr",
]
[[package]]
name = "winreg"
-version = "0.10.1"
+version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
+checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
dependencies = [
- "winapi",
+ "cfg-if",
+ "windows-sys",
]
[[package]]
diff --git a/kifu/gtk/Cargo.toml b/kifu/gtk/Cargo.toml
index 9e60660..14d015a 100644
--- a/kifu/gtk/Cargo.toml
+++ b/kifu/gtk/Cargo.toml
@@ -13,12 +13,12 @@ adw = { version = "0.4", package = "libadwaita", features = [ "v1_2" ] }
cairo-rs = { version = "0.17" }
gio = { version = "0.17" }
glib = { version = "0.17" }
-gtk = { version = "0.6", package = "gtk4", features = ["v4_8"] }
+gtk = { version = "0.6", package = "gtk4", features = [ "v4_8" ] }
image = { version = "0.24" }
kifu-core = { path = "../core" }
-tokio = { version = "1.26", features = [ "full" ] }
-# screenplay = { path = "../../screenplay" }
+pango = { version = "*" }
sgf = { path = "../../sgf" }
+tokio = { version = "1.26", features = [ "full" ] }
[build-dependencies]
glib-build-tools = "0.17"
diff --git a/kifu/gtk/build.rs b/kifu/gtk/build.rs
index 18b1e1e..6e5a750 100644
--- a/kifu/gtk/build.rs
+++ b/kifu/gtk/build.rs
@@ -1,7 +1,7 @@
fn main() {
glib_build_tools::compile_resources(
&["resources"],
- "resources/resources.gresources.xml",
+ "resources/gresources.xml",
"com.luminescent-dreams.kifu-gtk.gresource",
);
}
diff --git a/kifu/gtk/config b/kifu/gtk/config
index a387288..d7c6367 100644
--- a/kifu/gtk/config
+++ b/kifu/gtk/config
@@ -3,5 +3,5 @@
"name":"Savanni",
"rank":{"Kyu":10}
},
- "DatabasePath": "kifu/core/fixtures/five_games"
+ "DatabasePath": "/home/savanni/Documents/50 Ludoj/53 Kifu"
}
diff --git a/kifu/gtk/resources/resources.gresources.xml b/kifu/gtk/resources/gresources.xml
similarity index 85%
rename from kifu/gtk/resources/resources.gresources.xml
rename to kifu/gtk/resources/gresources.xml
index 31ca0a0..557a5ba 100644
--- a/kifu/gtk/resources/resources.gresources.xml
+++ b/kifu/gtk/resources/gresources.xml
@@ -2,5 +2,6 @@
wood_texture.jpg
+ style.css
diff --git a/kifu/gtk/resources/style.css b/kifu/gtk/resources/style.css
new file mode 100644
index 0000000..4282dcd
--- /dev/null
+++ b/kifu/gtk/resources/style.css
@@ -0,0 +1,3 @@
+.content {
+ padding: 8px;
+}
diff --git a/kifu/gtk/src/main.rs b/kifu/gtk/src/main.rs
index 3217134..614b1dc 100644
--- a/kifu/gtk/src/main.rs
+++ b/kifu/gtk/src/main.rs
@@ -2,12 +2,12 @@ use adw::prelude::*;
use kifu_core::{CoreApp, CoreRequest, CoreResponse};
use kifu_gtk::{
perftrace,
- ui::{ConfigurationPage, Home, Layout, PlayingField},
+ ui::{AppWindow, ConfigurationPage, Home, PlayingField},
CoreApi,
};
use std::sync::{Arc, RwLock};
-fn handle_response(api: CoreApi, layout: Layout, message: CoreResponse) {
+fn handle_response(api: CoreApi, app_window: &AppWindow, message: CoreResponse) {
let playing_field = Arc::new(RwLock::new(None));
match message {
CoreResponse::ConfigurationView(view) => perftrace("ConfigurationView", || {
@@ -22,7 +22,7 @@ fn handle_response(api: CoreApi, layout: Layout, message: CoreResponse) {
let api = api.clone();
let home = Home::new(api, view);
- layout.set_content(&home);
+ app_window.set_content(&home);
}),
CoreResponse::PlayingFieldView(view) => perftrace("PlayingFieldView", || {
let api = api.clone();
@@ -31,7 +31,7 @@ fn handle_response(api: CoreApi, layout: Layout, message: CoreResponse) {
if playing_field.is_none() {
perftrace("creating a new playing field", || {
let field = PlayingField::new(api, view);
- layout.set_content(&field);
+ app_window.set_content(&field);
*playing_field = Some(field);
})
} else {
@@ -87,6 +87,8 @@ fn main() {
let (gtk_tx, gtk_rx) =
gtk::glib::MainContext::channel::(gtk::glib::PRIORITY_DEFAULT);
+ let app_window = AppWindow::new(&app);
+
let api = CoreApi {
gtk_tx,
rt: runtime.clone(),
@@ -102,22 +104,13 @@ fn main() {
});
app.add_action(&action_config);
- let window = adw::ApplicationWindow::builder()
- .application(app)
- .width_request(800)
- .height_request(500)
- .build();
-
- let layout = Layout::new();
- window.set_content(Some(&layout));
-
- window.present();
+ app_window.window.present();
gtk_rx.attach(None, {
let api = api.clone();
move |message| {
perftrace("handle_response", || {
- handle_response(api.clone(), layout.clone(), message)
+ handle_response(api.clone(), &app_window, message)
});
Continue(true)
}
diff --git a/kifu/gtk/src/ui/home.rs b/kifu/gtk/src/ui/home.rs
index c9a166b..daf0691 100644
--- a/kifu/gtk/src/ui/home.rs
+++ b/kifu/gtk/src/ui/home.rs
@@ -131,7 +131,10 @@ impl Home {
players.append(&white_player);
*s.imp().white_player.borrow_mut() = Some(white_player.clone());
- let new_game_button = gtk::Button::builder().label(&view.start_game.label).build();
+ let new_game_button = gtk::Button::builder()
+ .css_classes(vec!["suggested-action"])
+ .label(&view.start_game.label)
+ .build();
s.append(&new_game_button);
let library = Library::new();
diff --git a/kifu/gtk/src/ui/layout.rs b/kifu/gtk/src/ui/layout.rs
deleted file mode 100644
index 5057bfc..0000000
--- a/kifu/gtk/src/ui/layout.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-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("Kifu")))
- .build();
-
- let app_menu = gio::Menu::new();
- let menu_item = gio::MenuItem::new(Some("Configuration"), Some("app.show-config"));
- app_menu.append_item(&menu_item);
-
- let hamburger = gtk::MenuButton::builder()
- .icon_name("open-menu-symbolic")
- .build();
- hamburger.set_menu_model(Some(&app_menu));
-
- header.pack_end(&hamburger);
-
- 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/library.rs b/kifu/gtk/src/ui/library.rs
index 9fc24ce..a2b42c6 100644
--- a/kifu/gtk/src/ui/library.rs
+++ b/kifu/gtk/src/ui/library.rs
@@ -1,4 +1,5 @@
use crate::ui::GamePreview;
+use adw::{prelude::*, subclass::prelude::*};
use glib::Object;
use gtk::{glib, prelude::*, subclass::prelude::*};
use kifu_core::ui::GamePreviewElement;
@@ -35,7 +36,7 @@ impl GameObject {
pub struct LibraryPrivate {
model: gio::ListStore,
- list_view: gtk::ListView,
+ list_view: gtk::ColumnView,
}
impl Default for LibraryPrivate {
@@ -43,6 +44,8 @@ impl Default for LibraryPrivate {
let vector: Vec = vec![];
let model = gio::ListStore::new(glib::types::Type::OBJECT);
model.extend_from_slice(&vector);
+
+ /*
let factory = gtk::SignalListItemFactory::new();
factory.connect_setup(move |_, list_item| {
@@ -72,10 +75,60 @@ impl Default for LibraryPrivate {
None => (),
};
});
+ */
let selection_model = gtk::NoSelection::new(Some(model.clone()));
- let list_view = gtk::ListView::new(Some(selection_model), Some(factory));
- list_view.set_hexpand(true);
+ let list_view = gtk::ColumnView::builder().model(&selection_model).build();
+
+ fn make_factory(bind: F) -> gtk::SignalListItemFactory
+ where
+ F: Fn(GamePreviewElement) -> String + 'static,
+ {
+ let factory = gtk::SignalListItemFactory::new();
+ factory.connect_setup(|_, list_item| {
+ list_item
+ .downcast_ref::()
+ .unwrap()
+ .set_child(Some(
+ >k::Label::builder()
+ .halign(gtk::Align::Start)
+ .ellipsize(pango::EllipsizeMode::End)
+ .build(),
+ ))
+ });
+ factory.connect_bind(move |_, list_item| {
+ let list_item = list_item.downcast_ref::().unwrap();
+ let game = list_item.item().and_downcast::().unwrap();
+ let preview = list_item.child().and_downcast::().unwrap();
+ match game.game() {
+ Some(game) => preview.set_text(&bind(game)),
+ None => (),
+ };
+ });
+ factory
+ }
+
+ list_view.append_column(>k::ColumnViewColumn::new(
+ Some("date"),
+ Some(make_factory(|g| g.date)),
+ ));
+ list_view.append_column(>k::ColumnViewColumn::new(
+ Some("title"),
+ Some(make_factory(|g| g.name)),
+ ));
+ list_view.append_column(>k::ColumnViewColumn::new(
+ Some("black"),
+ Some(make_factory(|g| g.black_player)),
+ ));
+ list_view.append_column(>k::ColumnViewColumn::new(
+ Some("white"),
+ Some(make_factory(|g| g.white_player)),
+ ));
+ list_view.append_column(>k::ColumnViewColumn::new(
+ Some("result"),
+ Some(make_factory(|g| g.result)),
+ ));
+
Self { model, list_view }
}
}
@@ -84,22 +137,22 @@ impl Default for LibraryPrivate {
impl ObjectSubclass for LibraryPrivate {
const NAME: &'static str = "Library";
type Type = Library;
- type ParentType = gtk::Box;
+ type ParentType = adw::Bin;
}
impl ObjectImpl for LibraryPrivate {}
impl WidgetImpl for LibraryPrivate {}
-impl BoxImpl for LibraryPrivate {}
+impl BinImpl for LibraryPrivate {}
glib::wrapper! {
- pub struct Library(ObjectSubclass) @extends gtk::Widget, gtk::Box;
+ pub struct Library(ObjectSubclass) @extends adw::Bin, gtk::Widget;
}
impl Library {
pub fn new() -> Self {
let s: Self = Object::builder().build();
- s.set_hexpand(true);
- s.append(&s.imp().list_view);
+
+ s.set_child(Some(&s.imp().list_view));
s
}
diff --git a/kifu/gtk/src/ui/mod.rs b/kifu/gtk/src/ui/mod.rs
index de1c5fe..5b5bfcd 100644
--- a/kifu/gtk/src/ui/mod.rs
+++ b/kifu/gtk/src/ui/mod.rs
@@ -1,3 +1,8 @@
+use adw::prelude::*;
+use gio::resources_lookup_data;
+use glib::IsA;
+use gtk::{prelude::*, STYLE_PROVIDER_PRIORITY_USER};
+
mod chat;
pub use chat::Chat;
@@ -10,9 +15,6 @@ 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;
@@ -27,3 +29,72 @@ pub use board::Board;
#[cfg(feature = "screenplay")]
pub use playing_field::playing_field_view;
+
+pub struct AppWindow {
+ pub window: adw::ApplicationWindow,
+ pub header: adw::HeaderBar,
+ pub content: adw::Bin,
+}
+
+impl AppWindow {
+ pub fn new(app: &adw::Application) -> Self {
+ let window = adw::ApplicationWindow::builder()
+ .application(app)
+ .width_request(800)
+ .height_request(500)
+ .build();
+
+ let stylesheet = String::from_utf8(
+ resources_lookup_data(
+ "/com/luminescent-dreams/kifu-gtk/style.css",
+ gio::ResourceLookupFlags::NONE,
+ )
+ .expect("stylesheet should just be available")
+ .to_vec(),
+ )
+ .expect("to parse stylesheet");
+
+ let provider = gtk::CssProvider::new();
+ provider.load_from_data(&stylesheet);
+ let context = window.style_context();
+ context.add_provider(&provider, STYLE_PROVIDER_PRIORITY_USER);
+
+ let header = adw::HeaderBar::builder()
+ .title_widget(>k::Label::new(Some("Kifu")))
+ .build();
+
+ let app_menu = gio::Menu::new();
+ let menu_item = gio::MenuItem::new(Some("Configuration"), Some("app.show-config"));
+ app_menu.append_item(&menu_item);
+
+ let hamburger = gtk::MenuButton::builder()
+ .icon_name("open-menu-symbolic")
+ .build();
+ hamburger.set_menu_model(Some(&app_menu));
+
+ header.pack_end(&hamburger);
+
+ let content = adw::Bin::builder().css_classes(vec!["content"]).build();
+ content.set_child(Some(
+ &adw::StatusPage::builder().title("Nothing here").build(),
+ ));
+
+ let layout = gtk::Box::builder()
+ .orientation(gtk::Orientation::Vertical)
+ .build();
+ layout.append(&header);
+ layout.append(&content);
+
+ window.set_content(Some(&layout));
+
+ Self {
+ window,
+ header,
+ content,
+ }
+ }
+
+ pub fn set_content(&self, content: &impl IsA) {
+ self.content.set_child(Some(content));
+ }
+}