Set up a configuration UI #66
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
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 std::sync::{Arc, RwLock};
|
||||
|
@ -12,6 +12,7 @@ use typeshare::typeshare;
|
|||
pub enum CoreRequest {
|
||||
CreateGame(CreateGameRequest),
|
||||
Home,
|
||||
OpenConfiguration,
|
||||
PlayingField,
|
||||
PlayStone(PlayStoneRequest),
|
||||
StartGame,
|
||||
|
@ -57,6 +58,7 @@ impl From<HotseatPlayerRequest> for Player {
|
|||
#[typeshare]
|
||||
#[serde(tag = "type", content = "content")]
|
||||
pub enum CoreResponse {
|
||||
ConfigurationView(ConfigurationView),
|
||||
HomeView(HomeView),
|
||||
PlayingFieldView(PlayingFieldView),
|
||||
}
|
||||
|
@ -116,6 +118,9 @@ impl CoreApp {
|
|||
CoreRequest::Home => {
|
||||
CoreResponse::HomeView(home(self.state.read().unwrap().database.all_games()))
|
||||
}
|
||||
CoreRequest::OpenConfiguration => {
|
||||
CoreResponse::ConfigurationView(configuration(&self.config))
|
||||
}
|
||||
CoreRequest::PlayingField => {
|
||||
let app_state = self.state.read().unwrap();
|
||||
let game = app_state.game.as_ref().unwrap();
|
||||
|
|
|
@ -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: (),
|
||||
},
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
}
|
|
@ -1,3 +1,31 @@
|
|||
pub mod action;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use typeshare::typeshare;
|
||||
|
||||
pub mod game_preview;
|
||||
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,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
mod configuration;
|
||||
pub use configuration::{configuration, ConfigurationView};
|
||||
|
||||
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;
|
||||
pub use playing_field::{playing_field, PlayingFieldView};
|
||||
|
|
|
@ -2,7 +2,7 @@ use adw::prelude::*;
|
|||
use kifu_core::{CoreApp, CoreRequest, CoreResponse};
|
||||
use kifu_gtk::{
|
||||
perftrace,
|
||||
ui::{Home, Layout, PlayingField},
|
||||
ui::{ConfigurationPage, Home, Layout, PlayingField},
|
||||
CoreApi,
|
||||
};
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
@ -10,6 +10,27 @@ use std::sync::{Arc, RwLock};
|
|||
fn handle_response(api: CoreApi, layout: Layout, message: CoreResponse) {
|
||||
let playing_field = Arc::new(RwLock::new(None));
|
||||
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", || {
|
||||
let api = api.clone();
|
||||
|
||||
|
@ -70,12 +91,6 @@ fn main() {
|
|||
.resource_base_path("/com/luminescent-dreams/kifu-gtk")
|
||||
.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({
|
||||
let runtime = runtime.clone();
|
||||
move |app| {
|
||||
|
@ -88,6 +103,15 @@ fn main() {
|
|||
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()
|
||||
.application(app)
|
||||
.width_request(800)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ pub struct LayoutPrivate {
|
|||
impl Default for LayoutPrivate {
|
||||
fn default() -> Self {
|
||||
let header = adw::HeaderBar::builder()
|
||||
.title_widget(>k::Label::new(Some("Placeholder Title")))
|
||||
.title_widget(>k::Label::new(Some("Kifu")))
|
||||
.build();
|
||||
|
||||
let app_menu = gio::Menu::new();
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
mod chat;
|
||||
pub use chat::Chat;
|
||||
|
||||
mod config;
|
||||
pub use config::ConfigurationPage;
|
||||
|
||||
mod game_preview;
|
||||
pub use game_preview::GamePreview;
|
||||
|
||||
|
|
Loading…
Reference in New Issue