diff --git a/ui/Cargo.lock b/ui/Cargo.lock
index 537d499..82788fc 100644
--- a/ui/Cargo.lock
+++ b/ui/Cargo.lock
@@ -2,6 +2,12 @@
# It is not intended for manual editing.
version = 4
+[[package]]
+name = "anyhow"
+version = "1.0.98"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
+
[[package]]
name = "autocfg"
version = "1.5.0"
@@ -570,6 +576,15 @@ dependencies = [
"serde",
]
+[[package]]
+name = "serde_spanned"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "slab"
version = "0.4.10"
@@ -602,7 +617,7 @@ dependencies = [
"cfg-expr",
"heck",
"pkg-config",
- "toml",
+ "toml 0.8.23",
"version-compare",
]
@@ -619,11 +634,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
dependencies = [
"serde",
- "serde_spanned",
- "toml_datetime",
+ "serde_spanned 0.6.9",
+ "toml_datetime 0.6.11",
"toml_edit",
]
+[[package]]
+name = "toml"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed0aee96c12fa71097902e0bb061a5e1ebd766a6636bb605ba401c45c1650eac"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned 1.0.0",
+ "toml_datetime 0.7.0",
+ "toml_parser",
+ "toml_writer",
+ "winnow",
+]
+
[[package]]
name = "toml_datetime"
version = "0.6.11"
@@ -633,6 +663,15 @@ dependencies = [
"serde",
]
+[[package]]
+name = "toml_datetime"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "toml_edit"
version = "0.22.27"
@@ -641,18 +680,36 @@ checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
dependencies = [
"indexmap",
"serde",
- "serde_spanned",
- "toml_datetime",
+ "serde_spanned 0.6.9",
+ "toml_datetime 0.6.11",
"winnow",
]
+[[package]]
+name = "toml_parser"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30"
+dependencies = [
+ "winnow",
+]
+
+[[package]]
+name = "toml_writer"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64"
+
[[package]]
name = "ui"
version = "0.1.0"
dependencies = [
+ "anyhow",
"glib-build-tools",
"gtk4",
"libadwaita",
+ "serde",
+ "toml 0.9.2",
]
[[package]]
diff --git a/ui/Cargo.toml b/ui/Cargo.toml
index 9684e1e..165bc6a 100644
--- a/ui/Cargo.toml
+++ b/ui/Cargo.toml
@@ -5,7 +5,10 @@ edition = "2024"
[dependencies]
gtk = { version = "0.10.0", package = "gtk4" }
-adw = { version = "0.8.0", package = "libadwaita" }
+adw = { version = "0.8.0", package = "libadwaita", features = ["v1_4"] }
+serde = { version = "1.0", features = ["derive"] }
+toml = "0.9.2"
+anyhow = "1.0"
[build-dependencies]
glib-build-tools = "0.21.0"
diff --git a/ui/rsc/pane/main.ui b/ui/rsc/pane/main.ui
new file mode 100644
index 0000000..0fea93d
--- /dev/null
+++ b/ui/rsc/pane/main.ui
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
diff --git a/ui/rsc/pane/sidebar.ui b/ui/rsc/pane/sidebar.ui
new file mode 100644
index 0000000..62edd8d
--- /dev/null
+++ b/ui/rsc/pane/sidebar.ui
@@ -0,0 +1,39 @@
+
+
+
+
diff --git a/ui/rsc/resources.gresource.xml b/ui/rsc/resources.gresource.xml
index 47fcd0e..5ef5672 100644
--- a/ui/rsc/resources.gresource.xml
+++ b/ui/rsc/resources.gresource.xml
@@ -2,6 +2,8 @@
window.ui
+ pane/main.ui
+ pane/sidebar.ui
pref/dropdown.ui
pref/number.ui
pref/entry.ui
diff --git a/ui/rsc/window.ui b/ui/rsc/window.ui
index 8eb1025..99ae122 100644
--- a/ui/rsc/window.ui
+++ b/ui/rsc/window.ui
@@ -11,132 +11,11 @@
300
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- vertical
- 12
- 12
- 12
- 12
-
-
- Create New Profile
- suggested-action
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
- never
-
-
- vertical
- 48
- 48
- 32
- 32
- 32
-
-
-
- Frame Generation
-
-
-
- Multiplier
-
-
-
-
-
- Flow Scale
-
-
-
-
-
- Performance Mode
- false
-
-
-
-
-
-
-
- Frame Generation
-
-
-
- HDR Mode
- false
-
-
-
-
-
- Experimental Present Mode
- 0
-
-
-
- - vsync/fifo
- - mailbox
- - immediate
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/ui/src/config.rs b/ui/src/config.rs
new file mode 100644
index 0000000..75c4a9d
--- /dev/null
+++ b/ui/src/config.rs
@@ -0,0 +1,129 @@
+use std::sync::{Arc, OnceLock, RwLock};
+
+use anyhow::Context;
+
+pub mod structs;
+pub use structs::*;
+
+/// Find the configuration file path based on environment variables
+fn find_config_file() -> String {
+ if let Some(path) = std::env::var("LSFG_CONFIG").ok() {
+ return path;
+ }
+
+ if let Some(xdg) = std::env::var("XDG_CONFIG_HOME").ok() {
+ return format!("{}/lsfg-vk/conf.toml", xdg);
+ }
+
+ if let Some(home) = std::env::var("HOME").ok() {
+ return format!("{}/.config/lsfg-vk/conf.toml", home);
+ }
+
+ "conf.toml".to_string()
+}
+
+static CONFIG: OnceLock>> = OnceLock::new();
+static CONFIG_WRITER: OnceLock> = OnceLock::new();
+
+///
+/// Load the configuration from the file and create a writer.
+///
+pub fn load_config() -> Result<(), anyhow::Error> {
+ // load the configuration file
+ let path = find_config_file();
+ let data = std::fs::read(path)
+ .context("Failed to read conf.toml")?;
+ let config: TomlConfig = toml::from_slice(&data)
+ .context("Failed to parse conf.toml")?;
+ CONFIG.set(Arc::new(RwLock::new(config)))
+ .ok().context("Failed to set configuration state")?;
+
+ // create the configuration writer thread
+ let (tx, rx) = std::sync::mpsc::channel::<()>();
+ CONFIG_WRITER.set(tx)
+ .ok().context("Failed to set configuration writer")?;
+
+ std::thread::spawn(move || {
+ let config = CONFIG.get().unwrap();
+ loop {
+ // wait for a signal to write the configuration
+ if let Err(_) = rx.recv() {
+ break;
+ }
+
+ // wait a bit to avoid excessive writes
+ std::thread::sleep(std::time::Duration::from_millis(200));
+
+ // empty the channel
+ while rx.try_recv().is_ok() {}
+
+ // write the configuration
+ eprintln!("Saving configuration...");
+ if let Ok(config) = config.try_read() {
+ if let Err(e) = save_config(&config) {
+ eprintln!("Failed to save configuration: {}", e);
+ } else {
+ eprintln!("Configuration saved successfully");
+ }
+ } else {
+ eprintln!("Failed to read configuration state");
+ }
+ }
+ });
+ Ok(())
+}
+
+///
+/// Get a snapshot of the current configuration
+///
+pub fn get_config() -> Result {
+ let conf = CONFIG.get()
+ .expect("Configuration not loaded")
+ .try_read()
+ .map(|config| config.clone());
+ if let Ok(config) = conf {
+ return Ok(config)
+ }
+
+ anyhow::bail!("Failed to read configuration state")
+}
+
+///
+/// Safely edit the configuration.
+///
+pub fn edit_config(f: F) -> Result<(), anyhow::Error>
+where
+ F: FnOnce(&mut TomlConfig)
+{
+ let mut config = CONFIG.get()
+ .expect("Configuration not loaded")
+ .write()
+ .map_err(|_| anyhow::anyhow!("Failed to acquire write lock on configuration"))?;
+
+ f(&mut config);
+
+ CONFIG_WRITER.get().unwrap().send(())
+ .context("Failed to send configuration update signal")
+}
+
+///
+/// Save the configuration to the file
+///
+/// # Arguments
+///
+/// `config` - The configuration to save
+///
+pub fn save_config(config: &TomlConfig) -> Result<(), anyhow::Error> {
+ let path = find_config_file();
+
+ let parent = std::path::Path::new(&path).parent()
+ .context("Failed to get parent directory of config path")?;
+ std::fs::create_dir_all(parent)
+ .context("Failed to create config directory")?;
+
+ let data = toml::to_string(config)
+ .context("Failed to serialize conf.toml")?;
+ std::fs::write(path, data)
+ .context("Failed to write conf.toml")?;
+ Ok(())
+}
diff --git a/ui/src/config/structs.rs b/ui/src/config/structs.rs
new file mode 100644
index 0000000..66121c1
--- /dev/null
+++ b/ui/src/config/structs.rs
@@ -0,0 +1,68 @@
+use serde::{Deserialize, Serialize};
+
+// multiplier
+#[derive(Debug, Clone, Deserialize, Serialize)]
+pub struct Multiplier(i64);
+impl Default for Multiplier {
+ fn default() -> Self { Multiplier(2) }
+}
+impl From for Multiplier {
+ fn from(value: i64) -> Self { Multiplier(value) }
+}
+
+// flow scale
+#[derive(Debug, Clone, Deserialize, Serialize)]
+pub struct FlowScale(f64);
+impl Default for FlowScale {
+ fn default() -> Self { FlowScale(1.0) }
+}
+impl From for FlowScale {
+ fn from(value: f64) -> Self { FlowScale(value) }
+}
+
+// present mode
+#[derive(Debug, Clone, Deserialize, Serialize)]
+pub enum PresentMode {
+ #[serde(rename = "fifo", alias = "vsync")]
+ Vsync,
+ #[serde(rename = "immediate")]
+ Immediate,
+ #[serde(rename = "mailbox")]
+ Mailbox,
+}
+impl Default for PresentMode {
+ fn default() -> Self { PresentMode::Vsync }
+}
+
+/// Global configuration for the application
+#[derive(Debug, Clone, Default, Deserialize, Serialize)]
+pub struct TomlGlobal {
+ pub dll: Option
+}
+
+/// Game-specific configuration
+#[derive(Debug, Clone, Deserialize, Serialize)]
+pub struct TomlGame {
+ pub exe: String,
+
+ #[serde(default)]
+ pub multiplier: Multiplier,
+ #[serde(default)]
+ pub flow_scale: FlowScale,
+ #[serde(default)]
+ pub performance_mode: bool,
+ #[serde(default)]
+ pub hdr_mode: bool,
+ #[serde(default)]
+ pub experimental_present_mode: PresentMode
+}
+
+/// Main configuration structure
+#[derive(Debug, Clone, Deserialize, Serialize)]
+pub struct TomlConfig {
+ pub version: i64,
+ #[serde(default)]
+ pub global: TomlGlobal,
+ #[serde(default)]
+ pub game: Vec
+}
diff --git a/ui/src/main.rs b/ui/src/main.rs
index 51af8fb..2bd44e0 100644
--- a/ui/src/main.rs
+++ b/ui/src/main.rs
@@ -1,9 +1,130 @@
-mod ui;
+use std::sync::{Arc, OnceLock, RwLock};
+
+use adw::{self, subclass::prelude::ObjectSubclassIsExt};
+use gtk::{gio, prelude::*};
+
+use crate::config::*;
+
+mod wrapper;
+mod config;
const APP_ID: &str = "gay.pancake.lsfg-vk.ConfigurationUi";
-fn main() {
- let app = ui::App::new(APP_ID)
- .expect("Failed to create application");
- app.run()
+#[derive(Debug)]
+struct State {
+ // ui state
+ selected_game: Option
+}
+
+static STATE: OnceLock>> = OnceLock::new();
+
+fn main() {
+ gio::resources_register_include!("ui.gresource")
+ .expect("Failed to register resources");
+ config::load_config()
+ .expect("Failed to load configuration");
+
+ // prepare the application state
+ STATE.set(Arc::new(RwLock::new(State {
+ selected_game: Some(0)
+ }))).expect("Failed to set application state");
+
+ // start the application
+ let app = adw::Application::builder()
+ .application_id(APP_ID)
+ .build();
+ app.connect_activate(build_ui);
+ app.run();
+}
+
+fn build_ui(app: &adw::Application) {
+ // create the main window
+ let window = wrapper::Window::new(app);
+ window.set_application(Some(app));
+
+ // register main pane signals
+ let main = window.imp().main.imp();
+
+ let pref_multiplier = main.pref_multiplier.imp();
+ pref_multiplier.number.connect_value_changed(|dropdown| {
+ if let Ok(state) = STATE.get().unwrap().try_read() {
+ if state.selected_game.is_none() {
+ return;
+ }
+
+ let multiplier = (dropdown.value() as i64).into();
+ let _ = config::edit_config(|config| {
+ config.game[state.selected_game.unwrap()]
+ .multiplier = multiplier;
+ });
+ }
+ });
+
+ let pref_flow_scale = main.pref_flow_scale.imp();
+ pref_flow_scale.slider.connect_value_changed(|slider| {
+ if let Ok(state) = STATE.get().unwrap().try_read() {
+ if state.selected_game.is_none() {
+ return;
+ }
+
+ let flow_scale = (slider.value() / 100.0).into();
+ let _ = config::edit_config(|config| {
+ config.game[state.selected_game.unwrap()]
+ .flow_scale = flow_scale;
+ });
+ }
+ });
+
+ let pref_performance_mode = main.pref_performance_mode.imp();
+ pref_performance_mode.switch.connect_state_notify(|switch| {
+ if let Ok(state) = STATE.get().unwrap().try_read() {
+ if state.selected_game.is_none() {
+ return;
+ }
+
+ let performance_mode = switch.state();
+ let _ = config::edit_config(|config| {
+ config.game[state.selected_game.unwrap()]
+ .performance_mode = performance_mode;
+ });
+ }
+ });
+
+ let pref_hdr_mode = main.pref_hdr_mode.imp();
+ pref_hdr_mode.switch.connect_state_notify(|switch| {
+ if let Ok(state) = STATE.get().unwrap().try_read() {
+ if state.selected_game.is_none() {
+ return;
+ }
+
+ let hdr_mode = switch.state();
+ let _ = config::edit_config(|config| {
+ config.game[state.selected_game.unwrap()]
+ .hdr_mode = hdr_mode;
+ });
+ }
+ });
+
+ let pref_experimental_present_mode = main.pref_experimental_present_mode.imp();
+ pref_experimental_present_mode.dropdown.connect_selected_notify(|dropdown| {
+ if let Ok(state) = STATE.get().unwrap().try_read() {
+ if state.selected_game.is_none() {
+ return;
+ }
+
+ let selected = match dropdown.selected() {
+ 0 => PresentMode::Vsync,
+ 1 => PresentMode::Mailbox,
+ 2 => PresentMode::Immediate,
+ _ => PresentMode::Vsync,
+ };
+ config::edit_config(|config| {
+ config.game[state.selected_game.unwrap()]
+ .experimental_present_mode = selected;
+ }).unwrap();
+ }
+ });
+
+ // present the window
+ window.present();
}
diff --git a/ui/src/ui.rs b/ui/src/ui.rs
deleted file mode 100644
index e11d734..0000000
--- a/ui/src/ui.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-use std::sync::Arc;
-
-use adw;
-use gtk::{gio, glib, prelude::*};
-
-pub mod ui;
-pub mod pref;
-
-pub struct App {
- app: Arc,
-}
-
-impl App {
- pub fn new(appid: &str) -> Result {
- gio::resources_register_include!("ui.gresource")?;
-
- let app = adw::Application::builder()
- .application_id(appid)
- .build();
- app.connect_activate(Self::build_ui);
-
- Ok(App {
- app: Arc::new(app)
- })
- }
-
- fn build_ui(app: &adw::Application) {
- let window = ui::Window::new(app);
- window.set_application(Some(app));
- window.present();
- }
-
- pub fn run(self){
- self.app.run();
- }
-}
diff --git a/ui/src/ui/ui.rs b/ui/src/ui/ui.rs
deleted file mode 100644
index d59f2f4..0000000
--- a/ui/src/ui/ui.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-use gtk::glib;
-use gtk;
-use adw;
-use gtk::glib::types::StaticTypeExt;
-
-pub mod window;
-
-glib::wrapper! {
- pub struct Window(ObjectSubclass)
- @extends
- adw::ApplicationWindow, adw::Window,
- gtk::ApplicationWindow, gtk::Window, gtk::Widget,
- @implements
- gtk::gio::ActionGroup, gtk::gio::ActionMap,
- gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget,
- gtk::Native, gtk::Root, gtk::ShortcutManager;
-}
-
-impl Window {
- pub fn new(app: &adw::Application) -> Self {
- super::pref::PrefDropdown::ensure_type();
- super::pref::PrefSwitch::ensure_type();
- super::pref::PrefEntry::ensure_type();
-
- glib::Object::builder()
- .property("application", app)
- .build()
- }
-}
diff --git a/ui/src/ui/ui/window.rs b/ui/src/ui/ui/window.rs
deleted file mode 100644
index 24b680b..0000000
--- a/ui/src/ui/ui/window.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-use gtk::{prelude::RangeExt, subclass::prelude::*};
-use adw::subclass::prelude::*;
-use crate::ui::pref::*;
-use gtk::{glib, CompositeTemplate};
-
-#[derive(CompositeTemplate, Default)]
-#[template(resource = "/gay/pancake/lsfg-vk/window.ui")]
-pub struct Window {
- // main config elements
- #[template_child]
- pref_multiplier: TemplateChild,
- #[template_child]
- pref_flow_scale: TemplateChild,
- #[template_child]
- pref_performance_mode: TemplateChild,
- #[template_child]
- pref_hdr_mode: TemplateChild,
- #[template_child]
- pref_experimental_present_mode: TemplateChild,
-}
-
-#[glib::object_subclass]
-impl ObjectSubclass for Window {
- const NAME: &'static str = "LSApplicationWindow";
- type Type = super::Window;
- type ParentType = adw::ApplicationWindow;
-
- fn class_init(klass: &mut Self::Class) {
- klass.bind_template();
- }
-
- fn instance_init(obj: &glib::subclass::InitializingObject) {
- obj.init_template();
- }
-}
-
-impl ObjectImpl for Window {
- fn constructed(&self) {
- self.parent_constructed();
-
- self.pref_multiplier.get()
- .imp().number.get().connect_value_changed(|dropdown| {
- let selected = dropdown.value();
- println!("Multiplier changed: {}", selected);
- });
- self.pref_flow_scale.get()
- .imp().slider.get().connect_value_changed(|slider| {
- let value = slider.value();
- println!("Flow scale changed: {}", value);
- });
- self.pref_performance_mode.get()
- .imp().switch.get().connect_state_notify(|switch| {
- let state = switch.state();
- println!("Performance mode changed: {}", state);
- });
- self.pref_hdr_mode.get()
- .imp().switch.get().connect_state_notify(|switch| {
- let state = switch.state();
- println!("HDR mode changed: {}", state);
- });
- self.pref_experimental_present_mode.get()
- .imp().dropdown.get().connect_selected_notify(|dropdown| {
- let selected = dropdown.selected();
- println!("Experimental present mode changed: {}", selected);
- });
- }
-}
-
-impl WidgetImpl for Window {}
-impl WindowImpl for Window {}
-impl ApplicationWindowImpl for Window {}
-impl AdwWindowImpl for Window {}
-impl AdwApplicationWindowImpl for Window {}
diff --git a/ui/src/wrapper.rs b/ui/src/wrapper.rs
new file mode 100644
index 0000000..5a981df
--- /dev/null
+++ b/ui/src/wrapper.rs
@@ -0,0 +1,77 @@
+use gtk::glib;
+use gtk;
+use adw;
+use gtk::glib::types::StaticTypeExt;
+
+pub mod pane;
+pub mod pref;
+
+pub mod imp {
+ use gtk::subclass::prelude::*;
+ use adw::subclass::prelude::*;
+ use crate::wrapper::pane::*;
+ use gtk::{glib, CompositeTemplate};
+
+ #[derive(CompositeTemplate, Default)]
+ #[template(resource = "/gay/pancake/lsfg-vk/window.ui")]
+ pub struct Window {
+ #[template_child]
+ pub main: TemplateChild,
+ #[template_child]
+ pub sidebar: TemplateChild,
+ }
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for Window {
+ const NAME: &'static str = "LSApplicationWindow";
+ type Type = super::Window;
+ type ParentType = adw::ApplicationWindow;
+
+ fn class_init(klass: &mut Self::Class) {
+ klass.bind_template();
+ }
+
+ fn instance_init(obj: &glib::subclass::InitializingObject) {
+ obj.init_template();
+ }
+ }
+
+ impl ObjectImpl for Window {
+ fn constructed(&self) {
+ self.parent_constructed();
+ }
+ }
+
+ impl WidgetImpl for Window {}
+ impl WindowImpl for Window {}
+ impl ApplicationWindowImpl for Window {}
+ impl AdwWindowImpl for Window {}
+ impl AdwApplicationWindowImpl for Window {}
+}
+
+glib::wrapper! {
+ pub struct Window(ObjectSubclass)
+ @extends
+ adw::ApplicationWindow, adw::Window,
+ gtk::ApplicationWindow, gtk::Window, gtk::Widget,
+ @implements
+ gtk::gio::ActionGroup, gtk::gio::ActionMap,
+ gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget,
+ gtk::Native, gtk::Root, gtk::ShortcutManager;
+}
+
+impl Window {
+ pub fn new(app: &adw::Application) -> Self {
+ pref::PrefDropdown::ensure_type();
+ pref::PrefEntry::ensure_type();
+ pref::PrefNumber::ensure_type();
+ pref::PrefSlider::ensure_type();
+ pref::PrefSwitch::ensure_type();
+ pane::PaneMain::ensure_type();
+ pane::PaneSidebar::ensure_type();
+
+ glib::Object::builder()
+ .property("application", app)
+ .build()
+ }
+}
diff --git a/ui/src/wrapper/pane.rs b/ui/src/wrapper/pane.rs
new file mode 100644
index 0000000..e9ac12e
--- /dev/null
+++ b/ui/src/wrapper/pane.rs
@@ -0,0 +1,35 @@
+use gtk::glib;
+use gtk;
+use adw;
+
+pub mod main;
+pub mod sidebar;
+
+glib::wrapper! {
+ pub struct PaneMain(ObjectSubclass)
+ @extends
+ adw::NavigationPage, gtk::Widget,
+ @implements
+ gtk::Accessible, gtk::Actionable, gtk::Buildable, gtk::ConstraintTarget;
+}
+
+glib::wrapper! {
+ pub struct PaneSidebar(ObjectSubclass)
+ @extends
+ adw::NavigationPage, gtk::Widget,
+ @implements
+ gtk::Accessible, gtk::Actionable, gtk::Buildable, gtk::ConstraintTarget;
+}
+
+
+impl PaneMain {
+ pub fn new() -> Self {
+ glib::Object::new()
+ }
+}
+
+impl PaneSidebar {
+ pub fn new() -> Self {
+ glib::Object::new()
+ }
+}
diff --git a/ui/src/wrapper/pane/main.rs b/ui/src/wrapper/pane/main.rs
new file mode 100644
index 0000000..853ea59
--- /dev/null
+++ b/ui/src/wrapper/pane/main.rs
@@ -0,0 +1,43 @@
+use gtk::glib;
+use gtk::subclass::prelude::*;
+use adw::subclass::prelude::*;
+use crate::wrapper::pref::*;
+
+#[derive(gtk::CompositeTemplate, Default)]
+#[template(resource = "/gay/pancake/lsfg-vk/pane/main.ui")]
+pub struct PaneMain {
+ #[template_child]
+ pub pref_multiplier: TemplateChild,
+ #[template_child]
+ pub pref_flow_scale: TemplateChild,
+ #[template_child]
+ pub pref_performance_mode: TemplateChild,
+ #[template_child]
+ pub pref_hdr_mode: TemplateChild,
+ #[template_child]
+ pub pref_experimental_present_mode: TemplateChild
+}
+
+#[glib::object_subclass]
+impl ObjectSubclass for PaneMain {
+ const NAME: &'static str = "LSPaneMain";
+ type Type = super::PaneMain;
+ type ParentType = adw::NavigationPage;
+
+ fn class_init(klass: &mut Self::Class) {
+ klass.bind_template();
+ }
+
+ fn instance_init(obj: &glib::subclass::InitializingObject) {
+ obj.init_template();
+ }
+}
+
+impl ObjectImpl for PaneMain {
+ fn constructed(&self) {
+ self.parent_constructed();
+ }
+}
+
+impl WidgetImpl for PaneMain {}
+impl NavigationPageImpl for PaneMain {}
diff --git a/ui/src/wrapper/pane/sidebar.rs b/ui/src/wrapper/pane/sidebar.rs
new file mode 100644
index 0000000..c43c31e
--- /dev/null
+++ b/ui/src/wrapper/pane/sidebar.rs
@@ -0,0 +1,33 @@
+use gtk::glib;
+use gtk::subclass::prelude::*;
+use adw::subclass::prelude::*;
+
+#[derive(gtk::CompositeTemplate, Default)]
+#[template(resource = "/gay/pancake/lsfg-vk/pane/sidebar.ui")]
+pub struct PaneSidebar {
+
+}
+
+#[glib::object_subclass]
+impl ObjectSubclass for PaneSidebar {
+ const NAME: &'static str = "LSPaneSidebar";
+ type Type = super::PaneSidebar;
+ type ParentType = adw::NavigationPage;
+
+ fn class_init(klass: &mut Self::Class) {
+ klass.bind_template();
+ }
+
+ fn instance_init(obj: &glib::subclass::InitializingObject) {
+ obj.init_template();
+ }
+}
+
+impl ObjectImpl for PaneSidebar {
+ fn constructed(&self) {
+ self.parent_constructed();
+ }
+}
+
+impl WidgetImpl for PaneSidebar {}
+impl NavigationPageImpl for PaneSidebar {}
diff --git a/ui/src/ui/pref.rs b/ui/src/wrapper/pref.rs
similarity index 100%
rename from ui/src/ui/pref.rs
rename to ui/src/wrapper/pref.rs
diff --git a/ui/src/ui/pref/dropdown.rs b/ui/src/wrapper/pref/dropdown.rs
similarity index 100%
rename from ui/src/ui/pref/dropdown.rs
rename to ui/src/wrapper/pref/dropdown.rs
diff --git a/ui/src/ui/pref/entry.rs b/ui/src/wrapper/pref/entry.rs
similarity index 100%
rename from ui/src/ui/pref/entry.rs
rename to ui/src/wrapper/pref/entry.rs
diff --git a/ui/src/ui/pref/number.rs b/ui/src/wrapper/pref/number.rs
similarity index 100%
rename from ui/src/ui/pref/number.rs
rename to ui/src/wrapper/pref/number.rs
diff --git a/ui/src/ui/pref/slider.rs b/ui/src/wrapper/pref/slider.rs
similarity index 100%
rename from ui/src/ui/pref/slider.rs
rename to ui/src/wrapper/pref/slider.rs
diff --git a/ui/src/ui/pref/switch.rs b/ui/src/wrapper/pref/switch.rs
similarity index 100%
rename from ui/src/ui/pref/switch.rs
rename to ui/src/wrapper/pref/switch.rs