Set up the settings user interface #225
|
@ -1,3 +1,8 @@
|
||||||
.content {
|
.content {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.settings-view {
|
||||||
|
margin: 8px;
|
||||||
|
background-color: @view_bg_color;
|
||||||
|
}
|
||||||
|
|
|
@ -19,9 +19,11 @@ use gio::resources_lookup_data;
|
||||||
use glib::IsA;
|
use glib::IsA;
|
||||||
use gtk::STYLE_PROVIDER_PRIORITY_USER;
|
use gtk::STYLE_PROVIDER_PRIORITY_USER;
|
||||||
use kifu_core::{Config, Core};
|
use kifu_core::{Config, Core};
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use crate::view_models::SettingsViewModel;
|
use crate::view_models::SettingsViewModel;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
enum AppView {
|
enum AppView {
|
||||||
Settings(SettingsViewModel),
|
Settings(SettingsViewModel),
|
||||||
Home,
|
Home,
|
||||||
|
@ -31,6 +33,7 @@ enum AppView {
|
||||||
// - an overlay widget
|
// - an overlay widget
|
||||||
// - the main content in a stack on the bottom panel of the overlay
|
// - the main content in a stack on the bottom panel of the overlay
|
||||||
// - the settings and the about page in bins atop the overlay
|
// - the settings and the about page in bins atop the overlay
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct AppWindow {
|
pub struct AppWindow {
|
||||||
pub window: adw::ApplicationWindow,
|
pub window: adw::ApplicationWindow,
|
||||||
header: adw::HeaderBar,
|
header: adw::HeaderBar,
|
||||||
|
@ -48,42 +51,14 @@ pub struct AppWindow {
|
||||||
// anywhere but shouldn't be part of the main application flow.
|
// anywhere but shouldn't be part of the main application flow.
|
||||||
panel_overlay: gtk::Overlay,
|
panel_overlay: gtk::Overlay,
|
||||||
core: Core,
|
core: Core,
|
||||||
|
|
||||||
|
// Not liking this, but I have to keep track of the settings view model separately from
|
||||||
|
// anything else. I'll have to look into this later.
|
||||||
|
settings_view_model: Arc<RwLock<Option<SettingsViewModel>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppWindow {
|
impl AppWindow {
|
||||||
pub fn new(app: &adw::Application, core: Core) -> Self {
|
pub fn new(app: &adw::Application, core: Core) -> Self {
|
||||||
/*
|
|
||||||
|
|
||||||
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 = setup_header();
|
|
||||||
|
|
||||||
let current_view = match config.get::<Database>() {
|
|
||||||
Some(_) => AppView::Home,
|
|
||||||
None => AppView::Config(SettingsViewModel::new(core.clone())),
|
|
||||||
};
|
|
||||||
|
|
||||||
let content = adw::Bin::builder().css_classes(vec!["content"]).build();
|
|
||||||
content.set_child(Some(
|
|
||||||
));
|
|
||||||
|
|
||||||
|
|
||||||
window.set_content(Some(&layout));
|
|
||||||
*/
|
|
||||||
|
|
||||||
let window = Self::setup_window(app);
|
let window = Self::setup_window(app);
|
||||||
let header = Self::setup_header();
|
let header = Self::setup_header();
|
||||||
let panel_overlay = Self::setup_panel_overlay();
|
let panel_overlay = Self::setup_panel_overlay();
|
||||||
|
@ -105,9 +80,16 @@ impl AppWindow {
|
||||||
content,
|
content,
|
||||||
panel_overlay,
|
panel_overlay,
|
||||||
core,
|
core,
|
||||||
|
settings_view_model: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn open_settings(&self) {
|
||||||
|
let view_model = SettingsViewModel::new(self.core.clone());
|
||||||
|
self.panel_overlay.add_overlay(&view_model.widget);
|
||||||
|
*self.settings_view_model.write().unwrap() = Some(view_model);
|
||||||
|
}
|
||||||
|
|
||||||
fn setup_window(app: &adw::Application) -> adw::ApplicationWindow {
|
fn setup_window(app: &adw::Application) -> adw::ApplicationWindow {
|
||||||
let window = adw::ApplicationWindow::builder()
|
let window = adw::ApplicationWindow::builder()
|
||||||
.application(app)
|
.application(app)
|
||||||
|
@ -124,7 +106,7 @@ impl AppWindow {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let app_menu = gio::Menu::new();
|
let app_menu = gio::Menu::new();
|
||||||
let menu_item = gio::MenuItem::new(Some("Configuration"), Some("app.show_config"));
|
let menu_item = gio::MenuItem::new(Some("Configuration"), Some("app.show_settings"));
|
||||||
app_menu.append_item(&menu_item);
|
app_menu.append_item(&menu_item);
|
||||||
|
|
||||||
let hamburger = gtk::MenuButton::builder()
|
let hamburger = gtk::MenuButton::builder()
|
||||||
|
|
|
@ -55,17 +55,17 @@ fn handle_response(api: CoreApi, app_window: &AppWindow, message: CoreResponse)
|
||||||
|
|
||||||
fn load_config(app_id: &str) -> Config {
|
fn load_config(app_id: &str) -> Config {
|
||||||
let settings = gio::Settings::new(app_id);
|
let settings = gio::Settings::new(app_id);
|
||||||
let db_path: String = settings.string("database-path").into();
|
let lib_path: String = settings.string("library-path").into();
|
||||||
let mut config = Config::new();
|
let mut config = Config::new();
|
||||||
config.set(ConfigOption::LibraryPath(db_path.into()));
|
config.set(ConfigOption::LibraryPath(lib_path.into()));
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_app_configuration_action(app: &adw::Application) {
|
fn setup_app_configuration_action(app: &adw::Application, app_window: AppWindow) {
|
||||||
println!("setup_app_configuration_action");
|
println!("setup_app_configuration_action");
|
||||||
let action = ActionEntry::builder("show_config")
|
let action = ActionEntry::builder("show_settings")
|
||||||
.activate(|_app: &adw::Application, _, _| {
|
.activate(move |_app: &adw::Application, _, _| {
|
||||||
println!("show configuration window");
|
app_window.open_settings();
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
app.add_action_entries([action]);
|
app.add_action_entries([action]);
|
||||||
|
@ -125,14 +125,21 @@ fn main() {
|
||||||
app.connect_activate({
|
app.connect_activate({
|
||||||
let runtime = runtime.clone();
|
let runtime = runtime.clone();
|
||||||
move |app| {
|
move |app| {
|
||||||
let app_window = AppWindow::new(app, core.clone());
|
let mut app_window = AppWindow::new(app, core.clone());
|
||||||
|
|
||||||
setup_app_configuration_action(app);
|
match *core.library() {
|
||||||
|
Some(_) => {},
|
||||||
|
None => app_window.open_settings(),
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_app_configuration_action(app, app_window.clone());
|
||||||
|
|
||||||
|
/*
|
||||||
let api = CoreApi {
|
let api = CoreApi {
|
||||||
rt: runtime.clone(),
|
rt: runtime.clone(),
|
||||||
core: core.clone(),
|
core: core.clone(),
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
let action_config = gio::SimpleAction::new("show-config", None);
|
let action_config = gio::SimpleAction::new("show-config", None);
|
||||||
|
|
|
@ -16,17 +16,19 @@ You should have received a copy of the GNU General Public License along with Kif
|
||||||
|
|
||||||
use crate::{views, LocalObserver, views::SettingsView};
|
use crate::{views, LocalObserver, views::SettingsView};
|
||||||
use kifu_core::{Core, CoreNotification};
|
use kifu_core::{Core, CoreNotification};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// SettingsViewModel
|
/// SettingsViewModel
|
||||||
///
|
///
|
||||||
/// Listens for messages from the core, and serves as intermediary between the Settings UI and the
|
/// Listens for messages from the core, and serves as intermediary between the Settings UI and the
|
||||||
/// core. Because it needs to respond to events from the core, it owns the widget, which allows it
|
/// core. Because it needs to respond to events from the core, it owns the widget, which allows it
|
||||||
/// to tell the widget to update after certain events.
|
/// to tell the widget to update after certain events.
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct SettingsViewModel {
|
pub struct SettingsViewModel {
|
||||||
core: Core,
|
core: Core,
|
||||||
// Technically, Settings doesn't care about any events from Core. We will keep this around for
|
// Technically, Settings doesn't care about any events from Core. We will keep this around for
|
||||||
// now as reference, until something which does care shows up.
|
// now as reference, until something which does care shows up.
|
||||||
notification_observer: LocalObserver<CoreNotification>,
|
notification_observer: Arc<LocalObserver<CoreNotification>>,
|
||||||
pub widget: views::SettingsView,
|
pub widget: views::SettingsView,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +40,7 @@ impl SettingsViewModel {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
core,
|
core,
|
||||||
notification_observer,
|
notification_observer: Arc::new(notification_observer),
|
||||||
widget: SettingsView::new(),
|
widget: SettingsView::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License along with Kif
|
||||||
|
|
||||||
use glib::Object;
|
use glib::Object;
|
||||||
use gtk::{prelude::*, subclass::prelude::*};
|
use gtk::{prelude::*, subclass::prelude::*};
|
||||||
|
use adw::prelude::*;
|
||||||
|
|
||||||
pub struct SettingsPrivate {}
|
pub struct SettingsPrivate {}
|
||||||
|
|
||||||
|
@ -23,7 +24,7 @@ pub struct SettingsPrivate {}
|
||||||
impl ObjectSubclass for SettingsPrivate {
|
impl ObjectSubclass for SettingsPrivate {
|
||||||
const NAME: &'static str = "Settings";
|
const NAME: &'static str = "Settings";
|
||||||
type Type = SettingsView;
|
type Type = SettingsView;
|
||||||
type ParentType = gtk::Box;
|
type ParentType = gtk::Frame;
|
||||||
|
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {}
|
Self {}
|
||||||
|
@ -32,15 +33,33 @@ impl ObjectSubclass for SettingsPrivate {
|
||||||
|
|
||||||
impl ObjectImpl for SettingsPrivate {}
|
impl ObjectImpl for SettingsPrivate {}
|
||||||
impl WidgetImpl for SettingsPrivate {}
|
impl WidgetImpl for SettingsPrivate {}
|
||||||
impl BoxImpl for SettingsPrivate {}
|
#[allow(deprecated)]
|
||||||
|
impl FrameImpl for SettingsPrivate {}
|
||||||
|
|
||||||
glib::wrapper! {
|
glib::wrapper! {
|
||||||
pub struct SettingsView(ObjectSubclass<SettingsPrivate>) @extends gtk::Box, gtk::Widget, @implements gtk::Orientable;
|
pub struct SettingsView(ObjectSubclass<SettingsPrivate>) @extends gtk::Frame, gtk::Widget, @implements gtk::Accessible, gtk::Buildable, gtk::Orientable;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SettingsView {
|
impl SettingsView {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let s: Self = Object::builder().build();
|
let s: Self = Object::builder().build();
|
||||||
|
|
||||||
|
let group = adw::PreferencesGroup::builder().build();
|
||||||
|
let library_row = adw::PreferencesRow::builder()
|
||||||
|
.title("Library Path")
|
||||||
|
.child(>k::Label::builder().label("Library Path").build())
|
||||||
|
.build();
|
||||||
|
group.add(&library_row);
|
||||||
|
|
||||||
|
let layout = gtk::Box::builder()
|
||||||
|
.orientation(gtk::Orientation::Vertical)
|
||||||
|
.vexpand(true)
|
||||||
|
.build();
|
||||||
|
layout.append(&group);
|
||||||
|
|
||||||
|
s.set_child(Some(&layout));
|
||||||
|
s.set_css_classes(&["settings-view"]);
|
||||||
|
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue