Set up a configuration UI #66

Merged
savanni merged 7 commits from kifu/configuration into main 2023-08-25 01:08:33 +00:00
9 changed files with 147 additions and 21 deletions
Showing only changes of commit 5439e2ac04 - Show all commits

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
types::{AppState, Config, DatabasePath, GameState, Player, Rank}, types::{AppState, Config, DatabasePath, GameState, Player, Rank},
ui::{home, playing_field, HomeView, PlayingFieldView}, ui::{configuration, home, playing_field, ConfigurationView, HomeView, PlayingFieldView},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
@ -12,6 +12,7 @@ use typeshare::typeshare;
pub enum CoreRequest { pub enum CoreRequest {
CreateGame(CreateGameRequest), CreateGame(CreateGameRequest),
Home, Home,
OpenConfiguration,
PlayingField, PlayingField,
PlayStone(PlayStoneRequest), PlayStone(PlayStoneRequest),
StartGame, StartGame,
@ -57,6 +58,7 @@ impl From<HotseatPlayerRequest> for Player {
#[typeshare] #[typeshare]
#[serde(tag = "type", content = "content")] #[serde(tag = "type", content = "content")]
pub enum CoreResponse { pub enum CoreResponse {
ConfigurationView(ConfigurationView),
HomeView(HomeView), HomeView(HomeView),
PlayingFieldView(PlayingFieldView), PlayingFieldView(PlayingFieldView),
} }
@ -116,6 +118,9 @@ impl CoreApp {
CoreRequest::Home => { CoreRequest::Home => {
CoreResponse::HomeView(home(self.state.read().unwrap().database.all_games())) CoreResponse::HomeView(home(self.state.read().unwrap().database.all_games()))
} }
CoreRequest::OpenConfiguration => {
CoreResponse::ConfigurationView(configuration(&self.config))
}
CoreRequest::PlayingField => { CoreRequest::PlayingField => {
let app_state = self.state.read().unwrap(); let app_state = self.state.read().unwrap();
let game = app_state.game.as_ref().unwrap(); let game = app_state.game.as_ref().unwrap();

View File

@ -0,0 +1,24 @@
use crate::{
types::{Config, DatabasePath},
ui::Field,
};
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
#[derive(Clone, Debug, Serialize, Deserialize)]
#[typeshare]
pub struct ConfigurationView {
pub library: Field<()>,
}
pub fn configuration(config: &Config) -> ConfigurationView {
let path: Option<DatabasePath> = config.get();
ConfigurationView {
library: Field {
id: "library-path-field".to_owned(),
label: "Library".to_owned(),
value: path.map(|path| path.to_string_lossy().into_owned()),
action: (),
},
}
}

View File

@ -1,10 +0,0 @@
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
#[derive(Clone, Debug, Serialize, Deserialize)]
#[typeshare]
pub struct Action<A> {
pub id: String,
pub label: String,
pub action: A,
}

View File

@ -1,3 +1,31 @@
pub mod action; use serde::{Deserialize, Serialize};
use typeshare::typeshare;
pub mod game_preview; pub mod game_preview;
pub mod menu; pub mod menu;
#[derive(Clone, Debug, Serialize, Deserialize)]
#[typeshare]
pub struct Action<A> {
pub id: String,
pub label: String,
pub action: A,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[typeshare]
pub struct Toggle<A> {
pub id: String,
pub label: String,
pub value: bool,
pub action: A,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[typeshare]
pub struct Field<A> {
pub id: String,
pub label: String,
pub value: Option<String>,
pub action: A,
}

View File

@ -1,5 +1,8 @@
mod configuration;
pub use configuration::{configuration, ConfigurationView};
mod elements; mod elements;
pub use elements::{action::Action, game_preview::GamePreviewElement, menu::Menu}; pub use elements::{game_preview::GamePreviewElement, menu::Menu, Action, Field, Toggle};
mod playing_field; mod playing_field;
pub use playing_field::{playing_field, PlayingFieldView}; pub use playing_field::{playing_field, PlayingFieldView};

View File

@ -2,7 +2,7 @@ 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, Layout, PlayingField}, ui::{ConfigurationPage, Home, Layout, PlayingField},
CoreApi, CoreApi,
}; };
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
@ -10,6 +10,27 @@ use std::sync::{Arc, RwLock};
fn handle_response(api: CoreApi, layout: Layout, 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::ConfigurationView(view) => perftrace("ConfigurationView", || {
/*
let config_group = adw::PreferencesGroup::builder().build();
config_group.add(
&adw::EntryRow::builder()
.name("library")
.title("Library path")
.build(),
);
let config_page = adw::PreferencesPage::new();
config_page.set_name(Some("preferences"));
config_page.add(&config_group);
*/
let config_page = ConfigurationPage::new(view);
let window = adw::PreferencesWindow::new();
window.add(&config_page);
window.set_visible_page(&config_page);
window.present();
}),
CoreResponse::HomeView(view) => perftrace("HomeView", || { CoreResponse::HomeView(view) => perftrace("HomeView", || {
let api = api.clone(); let api = api.clone();
@ -70,12 +91,6 @@ fn main() {
.resource_base_path("/com/luminescent-dreams/kifu-gtk") .resource_base_path("/com/luminescent-dreams/kifu-gtk")
.build(); .build();
let action_config = gio::SimpleAction::new("show-config", None);
action_config.connect_activate(|_, _| {
println!("trigger the configuration menu");
});
app.add_action(&action_config);
app.connect_activate({ app.connect_activate({
let runtime = runtime.clone(); let runtime = runtime.clone();
move |app| { move |app| {
@ -88,6 +103,15 @@ fn main() {
core: core.clone(), core: core.clone(),
}; };
let action_config = gio::SimpleAction::new("show-config", None);
action_config.connect_activate({
let api = api.clone();
move |_, _| {
api.dispatch(CoreRequest::OpenConfiguration);
}
});
app.add_action(&action_config);
let window = adw::ApplicationWindow::builder() let window = adw::ApplicationWindow::builder()
.application(app) .application(app)
.width_request(800) .width_request(800)

49
kifu/gtk/src/ui/config.rs Normal file
View File

@ -0,0 +1,49 @@
use adw::{prelude::*, subclass::prelude::*};
use glib::Object;
use kifu_core::ui::ConfigurationView;
#[derive(Default)]
pub struct ConfigurationPagePrivate {}
#[glib::object_subclass]
impl ObjectSubclass for ConfigurationPagePrivate {
const NAME: &'static str = "Configuration";
type Type = ConfigurationPage;
type ParentType = adw::PreferencesPage;
}
impl ObjectImpl for ConfigurationPagePrivate {}
impl WidgetImpl for ConfigurationPagePrivate {}
impl PreferencesPageImpl for ConfigurationPagePrivate {}
glib::wrapper! {
pub struct ConfigurationPage(ObjectSubclass<ConfigurationPagePrivate>)
@extends adw::PreferencesPage, gtk::Widget,
@implements gtk::Orientable;
}
impl ConfigurationPage {
pub fn new(view: ConfigurationView) -> Self {
let s: Self = Object::builder().build();
let group = adw::PreferencesGroup::builder().build();
let library_entry = &adw::EntryRow::builder()
.name("library-path")
.title(view.library.label)
.show_apply_button(true)
.build();
if let Some(path) = view.library.value {
library_entry.set_text(&path);
}
library_entry.connect_apply(|entry| {
println!("Set the library path to {}", entry.text());
});
group.add(library_entry);
s.add(&group);
s
}
}

View File

@ -12,7 +12,7 @@ pub struct LayoutPrivate {
impl Default for LayoutPrivate { impl Default for LayoutPrivate {
fn default() -> Self { fn default() -> Self {
let header = adw::HeaderBar::builder() let header = adw::HeaderBar::builder()
.title_widget(&gtk::Label::new(Some("Placeholder Title"))) .title_widget(&gtk::Label::new(Some("Kifu")))
.build(); .build();
let app_menu = gio::Menu::new(); let app_menu = gio::Menu::new();

View File

@ -1,6 +1,9 @@
mod chat; mod chat;
pub use chat::Chat; pub use chat::Chat;
mod config;
pub use config::ConfigurationPage;
mod game_preview; mod game_preview;
pub use game_preview::GamePreview; pub use game_preview::GamePreview;