diff --git a/Cargo.lock b/Cargo.lock index 2e8d6cd..62b7463 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,6 +10,8 @@ dependencies = [ "libloading", "native-windows-gui", "rand", + "serde", + "serde_json", "winapi", "winresource", ] @@ -28,9 +30,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "cfg-if" @@ -46,9 +48,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "libc", @@ -57,25 +59,31 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "indexmap" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", "hashbrown", ] +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] @@ -88,15 +96,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "libloading" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d580318f95776505201b28cf98eb1fa5e4be3b689633ba6a3e6cd880ff22d8cb" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" dependencies = [ "cfg-if", "windows-sys", @@ -110,15 +118,15 @@ checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "muldiv" @@ -154,24 +162,24 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "plotters" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" +checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" dependencies = [ "num-traits", "plotters-backend", @@ -181,9 +189,9 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" +checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" [[package]] name = "ppv-lite86" @@ -193,18 +201,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.28" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -239,17 +247,48 @@ dependencies = [ "getrandom", ] +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + [[package]] name = "serde" -version = "1.0.183" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "itoa", + "ryu", + "serde", +] [[package]] name = "serde_spanned" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" dependencies = [ "serde", ] @@ -266,9 +305,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" dependencies = [ "proc-macro2", "quote", @@ -277,9 +316,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ "serde", "serde_spanned", @@ -289,18 +328,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.14" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap", "serde", @@ -311,9 +350,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-segmentation" @@ -335,9 +374,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -345,9 +384,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", @@ -360,9 +399,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -370,9 +409,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", @@ -383,15 +422,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" dependencies = [ "js-sys", "wasm-bindgen", @@ -493,18 +532,18 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.4" +version = "0.5.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acaaa1190073b2b101e15083c38ee8ec891b5e05cbee516521e94ec008f61e64" +checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5" dependencies = [ "memchr", ] [[package]] name = "winresource" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ba0f9a8c8deba5c08bb4ca5a03bdc3068e572d9b8ae46738fd3a78504249c23" +checksum = "77e2aaaf8cfa92078c0c0375423d631f82f2f57979c2884fdd5f604a11e45329" dependencies = [ "toml", "version_check", diff --git a/Cargo.toml b/Cargo.toml index 411ed94..522a7f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,11 +17,13 @@ ProductName = "OLEDShift" ProductVersion = "1.1.1" [build-dependencies] -winresource = "0.1.16" +winresource = "0.1.17" [dependencies] lazy_static = "1.4.0" libloading = "0.8" -native-windows-gui = { version = "1.0.13", features = ["notice", "high-dpi", "number-select"]} +native-windows-gui = { version = "1.0.13", features = ["notice", "high-dpi", "number-select"] } rand = "0.8" -winapi = { version = "0.3", features = ["winuser", "shellapi"] } +winapi = { version = "0.3", features = ["winuser", "shellapi", "windef", "minwindef", "basetsd"] } +serde = { version = "1.0.193", features = ["derive"] } +serde_json = "1.0.108" diff --git a/src/controller.rs b/src/controller.rs index c0ddb35..de634d8 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -3,6 +3,7 @@ use std::thread; use std::thread::sleep; use std::time::Duration; use lazy_static::lazy_static; +use crate::settings::SettingsManager; use crate::mover; /// The delays that can be selected from the tray menu, in milliseconds @@ -50,37 +51,46 @@ impl Distances { } lazy_static! { + // This is a global variable that can be accessed from anywhere in the program + // It wasn't possible to pass the max move to the mover function since it's used in a C style callback, so this is the next best thing pub static ref MAX_MOVE: Mutex<(i32, i32)> = Mutex::new((50, 50)); } pub(crate) struct Controller { - interval: i32, - running: bool, + settings_manager: SettingsManager, } impl Default for Controller { fn default() -> Self { - Self { - interval: Delays::ThirtySeconds as i32, - running: true, - } + let controller = Controller { + settings_manager: SettingsManager::default(), + }; + controller.update_max_move(); + return controller; } } impl Controller { pub fn new() -> Self { - Self::default() + return Controller::default(); + } + + /// Sets the settings manager for the controller + pub fn set_settings(controller: Arc>, settings: SettingsManager) { + let mut controller = controller.lock().unwrap(); + controller.settings_manager = settings; + controller.update_max_move(); } pub fn run(controller: Arc>) { thread::Builder::new().name("mover_thread".to_string()).spawn(move || { - let interval = controller.lock().unwrap().interval as u64; + let interval = controller.lock().unwrap().get_interval() as u64; sleep(Duration::from_millis(interval)); // Wait for the first interval, don't move windows immediately loop { let controller = controller.lock().unwrap(); - let running = controller.running; - let interval = controller.interval as u64; + let running = controller.is_running(); + let interval = controller.get_interval() as u64; drop(controller); if running { @@ -93,26 +103,32 @@ impl Controller { } pub fn get_interval(&self) -> i32 { - self.interval + return self.settings_manager.get_delay(); } pub fn set_interval(&mut self, interval: i32) { - self.interval = interval; + self.settings_manager.set_delay(interval); } pub fn is_running(&self) -> bool { - self.running + return self.settings_manager.is_running(); } pub fn toggle_running(&mut self) { - self.running = !self.running; + self.settings_manager.toggle_running(); } pub fn get_max_move(&self) -> (i32, i32) { - return *MAX_MOVE.lock().unwrap(); + return self.settings_manager.get_max_distance(); } pub fn set_max_move(&mut self, max_move_x: i32, max_move_y: i32) { *MAX_MOVE.lock().unwrap() = (max_move_x, max_move_y); + self.settings_manager.set_max_distance(max_move_x, max_move_y); + } + + /// Updates the max move from the settings file, to be used on startup + fn update_max_move(&self) { + *MAX_MOVE.lock().unwrap() = self.settings_manager.get_max_distance(); } } diff --git a/src/delay_dialog.rs b/src/delay_dialog.rs index 152bdf1..5294f7d 100644 --- a/src/delay_dialog.rs +++ b/src/delay_dialog.rs @@ -1,5 +1,6 @@ use std::{thread, cell::RefCell}; use nwg::{ControlHandle, NativeUi, NumberSelectData}; +use crate::settings::{LOWEST_DELAY, MAX_DELAY}; pub enum DelayDialogData { Cancel, @@ -28,9 +29,9 @@ impl DelayDialog { let number_select_data = NumberSelectData::Int { value: (current_value / 1000) as i64, - step: 1, // 1 second - max: 1800, // 30 minutes - min: 1, // 1 second + step: 1, // 1 second steps + max: MAX_DELAY as i64, // 30 minutes + min: LOWEST_DELAY as i64, // 1 second }; app.number_select.set_data(number_select_data); diff --git a/src/distance_dialog.rs b/src/distance_dialog.rs index 9e29b61..dde2ee5 100644 --- a/src/distance_dialog.rs +++ b/src/distance_dialog.rs @@ -1,6 +1,7 @@ use crate::mover; use std::{thread, cell::RefCell}; use nwg::{ControlHandle, NativeUi, NumberSelectData}; +use crate::settings::LOWEST_MAX_DISTANCE; pub enum DistanceDialogData { Cancel, @@ -35,7 +36,7 @@ impl DistanceDialog { value: current_value_x as i64, step: 1, max: smallest_x as i64 / 4, - min: 1, + min: LOWEST_MAX_DISTANCE as i64, }; app.number_select_x.set_data(number_select_data_x); @@ -43,7 +44,7 @@ impl DistanceDialog { value: current_value_y as i64, step: 1, max: smallest_y as i64 / 4, - min: 1, + min: LOWEST_MAX_DISTANCE as i64, }; app.number_select_y.set_data(number_select_data_y); diff --git a/src/main.rs b/src/main.rs index 38d2a7f..fca0228 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,7 @@ mod mover; mod controller; mod delay_dialog; mod distance_dialog; +mod settings; fn main() { diff --git a/src/mover.rs b/src/mover.rs index c0d351b..e5c6e07 100644 --- a/src/mover.rs +++ b/src/mover.rs @@ -46,7 +46,7 @@ use winapi::{ WINDOWPLACEMENT }, }; -use winapi::um::winuser::{GetClassNameW, GetWindowTextW}; +use winapi::um::winuser::GetClassNameW; use crate::controller::{MAX_MOVE}; diff --git a/src/settings.rs b/src/settings.rs new file mode 100644 index 0000000..556b647 --- /dev/null +++ b/src/settings.rs @@ -0,0 +1,234 @@ +use std::fs::{File, write}; +use std::io::Read; +use std::sync::{Arc, Mutex}; +use serde::{Deserialize, Serialize}; +use crate::controller::Delays; + +#[derive(Serialize, Deserialize)] +pub struct Settings { + running: bool, + delay_milliseconds: i32, + max_distance_x: i32, + max_distance_y: i32, +} + +/// Lowest delay allowed, in milliseconds (1 second) +pub const LOWEST_DELAY: i32 = 1000; + +/// Highest delay allowed, in milliseconds (30 minutes) +pub const MAX_DELAY: i32 = 1800000; + +/// Lowest max distance allowed, in pixels +pub const LOWEST_MAX_DISTANCE: i32 = 1; + +impl Settings { + fn default() -> Self { + // The default settings + return Settings { + running: true, + delay_milliseconds: Delays::ThirtySeconds as i32, + max_distance_x: 50, + max_distance_y: 50, + }; + } + + pub fn get_running(&self) -> bool { + return self.running; + } + + pub fn set_running(&mut self, running: bool) { + self.running = running; + } + + /// Returns the delay in milliseconds + pub fn get_delay(&self) -> i32 { + return self.delay_milliseconds; + } + + /// Sets the delay, in milliseconds + pub fn set_delay(&mut self, delay: i32) { + self.delay_milliseconds = delay; + } + + /// Returns the delay in seconds + pub fn get_delay_seconds(&self) -> i32 { + return self.delay_milliseconds / 1000; + } + + /// Sets the delay, in seconds + pub fn set_delay_seconds(&mut self, delay: i32) { + self.delay_milliseconds = delay * 1000; + } + + pub fn get_max_distance(&self) -> (i32, i32) { + return (self.max_distance_x, self.max_distance_y); + } + + pub fn set_max_distance(&mut self, max_distance_x: i32, max_distance_y: i32) { + self.max_distance_x = max_distance_x; + self.max_distance_y = max_distance_y; + } +} + + + +const PATH: &str = "settings.json"; + +pub struct SettingsManager { + settings: Arc>, +} + +impl Default for SettingsManager { + fn default() -> Self { + return SettingsManager { + settings: Arc::new(Mutex::new(Settings::default())), + }; + } +} + +impl SettingsManager { + pub fn new() -> Result { + println!("Loading settings..."); + + if !std::path::Path::new(PATH).exists() { + println!("No settings file found, creating default settings..."); + let settings = Settings::default(); + let serialized = serde_json::to_string_pretty(&settings).unwrap(); + if let Err(err) = write(PATH, serialized) { + eprintln!("Failed to create the default settings file: {}", err); + } + } + + let result = File::open(PATH) + .and_then(|mut file| { + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + Ok(serde_json::from_str::(&contents)?) + }); + + return match result { + Ok(mut settings) => { + let mut errors: Vec = Vec::new(); + + // Validate the settings and update them if necessary since the user could have edited the settings file + if settings.delay_milliseconds < LOWEST_DELAY { + settings.delay_milliseconds = LOWEST_DELAY; + errors.push( + format!("The delay was too low, it has been set to the lowest possible value of {} second.", LOWEST_DELAY / 1000) + ); + } + if settings.delay_milliseconds > MAX_DELAY { + settings.delay_milliseconds = MAX_DELAY; + errors.push( + format!("The delay was too high, it has been set to the highest possible value of {} seconds.", MAX_DELAY / 1000) + ); + } + + if settings.max_distance_x < LOWEST_MAX_DISTANCE { + settings.max_distance_x = LOWEST_MAX_DISTANCE; + errors.push( + format!("The max distance X was too low, it has been set to the lowest possible value of {} pixel.", LOWEST_MAX_DISTANCE) + ); + } + if settings.max_distance_y < LOWEST_MAX_DISTANCE { + settings.max_distance_y = LOWEST_MAX_DISTANCE; + errors.push( + format!("The max distance Y was too low, it has been set to the lowest possible value of {} pixel.", LOWEST_MAX_DISTANCE) + ); + } + + if !errors.is_empty() { + println!("Found invalid values in the settings file!"); + + // Update the settings file with the valid settings + let serialized = serde_json::to_string_pretty(&settings).expect("Failed to serialize the settings"); + if let Err(err) = write(PATH, serialized) { + eprintln!("Failed to update the settings file: {}", err); + } + + return Err(( + errors.join("\n"), + SettingsManager::default(), + )); + } + + println!("Settings loaded successfully!"); + Ok(SettingsManager { + settings: Arc::new(Mutex::new(settings)), + }) + } + Err(err) => { + // Send the error message back to the UI with the default settings + Err(( + err.to_string(), + SettingsManager::default(), + )) + } + } + } + + /// Serializes and saves the settings to the settings file + fn save_settings(settings: &Settings) { + let serialized = serde_json::to_string_pretty(settings).unwrap(); + write(PATH, serialized).unwrap(); + } + + // --------------------------------------------------------------------------------------------- + // Getters and setters + // --------------------------------------------------------------------------------------------- + + pub fn is_running(&self) -> bool { + let settings = self.settings.lock().unwrap(); + return settings.running; + } + + /// Sets the running state, and saves the settings to the settings file + pub fn set_running(&self, running: bool) { + let mut settings = self.settings.lock().unwrap(); + settings.running = running; + SettingsManager::save_settings(&*settings); + } + + /// Toggles the running state, and saves the settings to the settings file + pub fn toggle_running(&self) { + let mut settings = self.settings.lock().unwrap(); + settings.running = !settings.running; + SettingsManager::save_settings(&*settings); + } + + pub fn get_delay(&self) -> i32 { + let settings = self.settings.lock().unwrap(); + return settings.delay_milliseconds; + } + + /// Sets the delay, in milliseconds, and saves the settings to the settings file + pub fn set_delay(&self, delay: i32) { + let mut settings = self.settings.lock().unwrap(); + settings.delay_milliseconds = delay; + SettingsManager::save_settings(&*settings); + } + + pub fn get_delay_seconds(&self) -> i32 { + let settings = self.settings.lock().unwrap(); + return settings.get_delay_seconds(); + } + + /// Sets the delay, in seconds, and saves the settings to the settings file + pub fn set_delay_seconds(&self, delay: i32) { + let mut settings = self.settings.lock().unwrap(); + settings.set_delay_seconds(delay); + SettingsManager::save_settings(&*settings); + } + + pub fn get_max_distance(&self) -> (i32, i32) { + let settings = self.settings.lock().unwrap(); + return settings.get_max_distance(); + } + + /// Sets the max distance, in pixels, and saves the settings to the settings file + pub fn set_max_distance(&self, max_distance_x: i32, max_distance_y: i32) { + let mut settings = self.settings.lock().unwrap(); + settings.set_max_distance(max_distance_x, max_distance_y); + SettingsManager::save_settings(&*settings); + } +} diff --git a/src/view.rs b/src/view.rs index 087c1be..b809773 100644 --- a/src/view.rs +++ b/src/view.rs @@ -35,16 +35,6 @@ pub struct SystemTray { } impl SystemTray { - - fn new(&self) -> Self { - let controller = Arc::new(Mutex::new(Controller::new())); - - return SystemTray { - controller, - ..Default::default() - }; - } - fn show_menu(&self) { let (x, y) = nwg::GlobalCursor::position(); self.tray_menu.popup(x, y); @@ -66,6 +56,12 @@ impl SystemTray { self.tray.show("OLEDShift", Some("OLEDShift is running in the system tray"), Some(flags), Some(&self.icon)); } + /// Shows the failed to parse the config file error message + fn show_config_parse_failed_message(&self, error_message: &str) { + let message = format!("Failed to parse the config file!\nThe default settings will be used instead.\n\nError: {}", error_message); + nwg::modal_error_message(&self.window, "Config parsing failed", &message); + } + fn do_delay(&self, delay: Delays) { match delay { Delays::ThirtySeconds => self.controller.lock().unwrap().set_interval(Delays::ThirtySeconds as i32), @@ -256,6 +252,7 @@ mod system_tray_ui { use std::cell::RefCell; use std::ops::Deref; use crate::controller::{Controller, Delays, Distances}; + use crate::settings::SettingsManager; use crate::view::{ICON, SystemTray}; pub struct SystemTrayUi { @@ -380,6 +377,12 @@ mod system_tray_ui { default_handler: Default::default(), }; + // Setup the controller + let settings_manager = SettingsManager::new().unwrap_or_else(|(err, manager)| { + ui.inner.show_config_parse_failed_message(&err); + return manager; + }); + Controller::set_settings(ui.inner.controller.clone(), settings_manager); // Start the controller Controller::run(ui.inner.controller.clone());