diff --git a/Cargo.lock b/Cargo.lock index 01b3f36..4885237 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -846,6 +846,27 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -1438,6 +1459,17 @@ dependencies = [ "windows-link", ] +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "getrandom" version = "0.3.4" @@ -2184,6 +2216,7 @@ name = "k-launcher" version = "0.1.0" dependencies = [ "iced", + "k-launcher-config", "k-launcher-kernel", "k-launcher-os-bridge", "k-launcher-ui", @@ -2195,6 +2228,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "k-launcher-config" +version = "0.1.0" +dependencies = [ + "dirs", + "serde", + "toml", +] + [[package]] name = "k-launcher-kernel" version = "0.1.0" @@ -2209,6 +2251,7 @@ dependencies = [ name = "k-launcher-os-bridge" version = "0.1.0" dependencies = [ + "k-launcher-config", "k-launcher-kernel", "libc", ] @@ -2218,6 +2261,7 @@ name = "k-launcher-ui" version = "0.1.0" dependencies = [ "iced", + "k-launcher-config", "k-launcher-kernel", "k-launcher-os-bridge", "tokio", @@ -2229,6 +2273,7 @@ version = "0.1.0" dependencies = [ "eframe", "egui", + "k-launcher-config", "k-launcher-kernel", "k-launcher-os-bridge", "tokio", @@ -3082,6 +3127,12 @@ version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "orbclient" version = "0.3.51" @@ -3372,7 +3423,7 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit", + "toml_edit 0.25.4+spec-1.1.0", ] [[package]] @@ -3612,6 +3663,17 @@ dependencies = [ "bitflags 2.11.0", ] +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 1.0.69", +] + [[package]] name = "renderdoc-sys" version = "1.1.0" @@ -3821,6 +3883,15 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "shlex" version = "1.3.0" @@ -4288,6 +4359,27 @@ dependencies = [ "syn", ] +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + [[package]] name = "toml_datetime" version = "1.0.0+spec-1.1.0" @@ -4297,6 +4389,20 @@ dependencies = [ "serde_core", ] +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_write", + "winnow", +] + [[package]] name = "toml_edit" version = "0.25.4+spec-1.1.0" @@ -4304,7 +4410,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2" dependencies = [ "indexmap", - "toml_datetime", + "toml_datetime 1.0.0+spec-1.1.0", "toml_parser", "winnow", ] @@ -4318,6 +4424,12 @@ dependencies = [ "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "tracing" version = "0.1.44" @@ -4534,6 +4646,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + [[package]] name = "wasip2" version = "1.0.2+wasi-0.2.9" @@ -5309,6 +5427,15 @@ dependencies = [ "windows-targets 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -5351,6 +5478,21 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -5382,6 +5524,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -5394,6 +5542,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -5406,6 +5560,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -5424,6 +5584,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -5436,6 +5602,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -5448,6 +5620,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -5460,6 +5638,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" diff --git a/Cargo.toml b/Cargo.toml index a6f46f8..bbf1455 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ "crates/k-launcher", + "crates/k-launcher-config", "crates/k-launcher-kernel", "crates/k-launcher-os-bridge", "crates/k-launcher-ui", @@ -14,8 +15,10 @@ resolver = "2" [workspace.dependencies] async-trait = "0.1" +dirs = "5.0" futures = "0.3" iced = { version = "0.14", features = ["image", "svg", "tokio", "tiny-skia"] } serde = { version = "1.0", features = ["derive"] } tokio = { version = "1.35", features = ["rt-multi-thread", "macros"] } +toml = "0.8" tracing = "0.1" diff --git a/crates/k-launcher-config/Cargo.toml b/crates/k-launcher-config/Cargo.toml new file mode 100644 index 0000000..b2df0a2 --- /dev/null +++ b/crates/k-launcher-config/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "k-launcher-config" +version = "0.1.0" +edition = "2024" + +[lib] +name = "k_launcher_config" +path = "src/lib.rs" + +[dependencies] +dirs = { workspace = true } +serde = { workspace = true } +toml = { workspace = true } diff --git a/crates/k-launcher-config/src/lib.rs b/crates/k-launcher-config/src/lib.rs new file mode 100644 index 0000000..154ed23 --- /dev/null +++ b/crates/k-launcher-config/src/lib.rs @@ -0,0 +1,193 @@ +use serde::Deserialize; + +// RGBA: [r, g, b, a] where r/g/b are 0–255 as f32, a is 0.0–1.0 +pub type Rgba = [f32; 4]; + +#[derive(Debug, Clone, Deserialize)] +#[serde(default)] +pub struct Config { + pub window: WindowCfg, + pub appearance: AppearanceCfg, + pub search: SearchCfg, + pub plugins: PluginsCfg, +} + +impl Default for Config { + fn default() -> Self { + Self { + window: WindowCfg::default(), + appearance: AppearanceCfg::default(), + search: SearchCfg::default(), + plugins: PluginsCfg::default(), + } + } +} + +#[derive(Debug, Clone, Deserialize)] +#[serde(default)] +pub struct WindowCfg { + pub width: f32, + pub height: f32, + pub decorations: bool, + pub transparent: bool, + pub resizable: bool, +} + +impl Default for WindowCfg { + fn default() -> Self { + Self { + width: 600.0, + height: 400.0, + decorations: false, + transparent: true, + resizable: false, + } + } +} + +#[derive(Debug, Clone, Deserialize)] +#[serde(default)] +pub struct AppearanceCfg { + pub background_rgba: Rgba, + pub border_rgba: Rgba, + pub border_width: f32, + pub border_radius: f32, + pub search_font_size: f32, + pub title_size: f32, + pub desc_size: f32, + pub row_radius: f32, + pub placeholder: String, +} + +impl Default for AppearanceCfg { + fn default() -> Self { + Self { + background_rgba: [20.0, 20.0, 30.0, 0.9], + border_rgba: [0.0, 183.0, 235.0, 1.0], + border_width: 1.0, + border_radius: 8.0, + search_font_size: 18.0, + title_size: 15.0, + desc_size: 12.0, + row_radius: 4.0, + placeholder: "Search...".to_string(), + } + } +} + +#[derive(Debug, Clone, Deserialize)] +#[serde(default)] +pub struct SearchCfg { + pub max_results: usize, +} + +impl Default for SearchCfg { + fn default() -> Self { + Self { max_results: 8 } + } +} + +#[derive(Debug, Clone, Deserialize)] +#[serde(default)] +pub struct PluginsCfg { + pub calc: bool, + pub cmd: bool, + pub files: bool, + pub apps: bool, +} + +impl Default for PluginsCfg { + fn default() -> Self { + Self { + calc: true, + cmd: true, + files: true, + apps: true, + } + } +} + +pub fn load() -> Config { + let path = dirs::config_dir() + .map(|d| d.join("k-launcher").join("config.toml")); + let Some(path) = path else { + return Config::default(); + }; + let Ok(content) = std::fs::read_to_string(&path) else { + return Config::default(); + }; + toml::from_str(&content).unwrap_or_default() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn default_config_has_sane_values() { + let cfg = Config::default(); + assert_eq!(cfg.search.max_results, 8); + assert_eq!(cfg.window.width, 600.0); + assert_eq!(cfg.window.height, 400.0); + assert!(!cfg.window.decorations); + assert!(cfg.window.transparent); + assert!(!cfg.window.resizable); + assert!(cfg.plugins.calc); + assert!(cfg.plugins.apps); + assert_eq!(cfg.appearance.search_font_size, 18.0); + assert_eq!(cfg.appearance.placeholder, "Search..."); + } + + #[test] + fn parse_partial_toml_uses_defaults() { + let toml = "[search]\nmax_results = 5\n"; + let cfg: Config = toml::from_str(toml).unwrap(); + assert_eq!(cfg.search.max_results, 5); + assert_eq!(cfg.window.width, 600.0); + assert_eq!(cfg.appearance.search_font_size, 18.0); + assert!(cfg.plugins.apps); + } + + #[test] + fn parse_full_toml_roundtrip() { + let toml = r#" +[window] +width = 800.0 +height = 500.0 +decorations = true +transparent = false +resizable = true + +[appearance] +background_rgba = [10.0, 10.0, 20.0, 0.8] +border_rgba = [100.0, 200.0, 255.0, 1.0] +border_width = 2.0 +border_radius = 12.0 +search_font_size = 20.0 +title_size = 16.0 +desc_size = 13.0 +row_radius = 6.0 +placeholder = "Type here..." + +[search] +max_results = 12 + +[plugins] +calc = false +cmd = true +files = false +apps = true +"#; + let cfg: Config = toml::from_str(toml).unwrap(); + assert_eq!(cfg.window.width, 800.0); + assert_eq!(cfg.window.height, 500.0); + assert!(cfg.window.decorations); + assert!(!cfg.window.transparent); + assert_eq!(cfg.appearance.background_rgba, [10.0, 10.0, 20.0, 0.8]); + assert_eq!(cfg.appearance.search_font_size, 20.0); + assert_eq!(cfg.appearance.placeholder, "Type here..."); + assert_eq!(cfg.search.max_results, 12); + assert!(!cfg.plugins.calc); + assert!(!cfg.plugins.files); + } +} diff --git a/crates/k-launcher-kernel/src/lib.rs b/crates/k-launcher-kernel/src/lib.rs index 0b4432c..0d48a24 100644 --- a/crates/k-launcher-kernel/src/lib.rs +++ b/crates/k-launcher-kernel/src/lib.rs @@ -101,11 +101,12 @@ pub trait SearchEngine: Send + Sync { pub struct Kernel { plugins: Vec>, + max_results: usize, } impl Kernel { - pub fn new(plugins: Vec>) -> Self { - Self { plugins } + pub fn new(plugins: Vec>, max_results: usize) -> Self { + Self { plugins, max_results } } pub async fn search(&self, query: &str) -> Vec { @@ -113,7 +114,7 @@ impl Kernel { let nested: Vec> = join_all(futures).await; let mut flat: Vec = nested.into_iter().flatten().collect(); flat.sort_by(|a, b| b.score.cmp(&a.score)); - flat.truncate(8); + flat.truncate(self.max_results); flat } } @@ -181,7 +182,7 @@ mod tests { #[tokio::test] async fn empty_kernel_returns_empty() { - let k = Kernel::new(vec![]); + let k = Kernel::new(vec![], 8); assert!(k.search("x").await.is_empty()); } @@ -192,10 +193,26 @@ mod tests { ("higher", 10), ("middle", 7), ])); - let k = Kernel::new(vec![plugin]); + let k = Kernel::new(vec![plugin], 8); let results = k.search("q").await; assert_eq!(results[0].score.value(), 10); assert_eq!(results[1].score.value(), 7); assert_eq!(results[2].score.value(), 5); } + + #[tokio::test] + async fn kernel_truncates_at_max_results() { + let plugin = Arc::new(MockPlugin::returns(vec![ + ("a", 10), + ("b", 9), + ("c", 8), + ("d", 7), + ("e", 6), + ])); + let k = Kernel::new(vec![plugin], 3); + let results = k.search("q").await; + assert_eq!(results.len(), 3); + assert_eq!(results[0].score.value(), 10); + assert_eq!(results[2].score.value(), 8); + } } diff --git a/crates/k-launcher-os-bridge/Cargo.toml b/crates/k-launcher-os-bridge/Cargo.toml index 6c82834..21ee736 100644 --- a/crates/k-launcher-os-bridge/Cargo.toml +++ b/crates/k-launcher-os-bridge/Cargo.toml @@ -4,5 +4,6 @@ version = "0.1.0" edition = "2024" [dependencies] +k-launcher-config = { path = "../k-launcher-config" } k-launcher-kernel = { path = "../k-launcher-kernel" } libc = "0.2" diff --git a/crates/k-launcher-os-bridge/src/lib.rs b/crates/k-launcher-os-bridge/src/lib.rs index 89bb1e1..3c4b717 100644 --- a/crates/k-launcher-os-bridge/src/lib.rs +++ b/crates/k-launcher-os-bridge/src/lib.rs @@ -11,13 +11,13 @@ pub struct WindowConfig { } impl WindowConfig { - pub fn launcher() -> Self { + pub fn from_cfg(w: &k_launcher_config::WindowCfg) -> Self { Self { - width: 600.0, - height: 400.0, - decorations: false, - transparent: true, - resizable: false, + width: w.width, + height: w.height, + decorations: w.decorations, + transparent: w.transparent, + resizable: w.resizable, } } } diff --git a/crates/k-launcher-ui-egui/Cargo.toml b/crates/k-launcher-ui-egui/Cargo.toml index 1d88b78..62be894 100644 --- a/crates/k-launcher-ui-egui/Cargo.toml +++ b/crates/k-launcher-ui-egui/Cargo.toml @@ -10,6 +10,7 @@ path = "src/lib.rs" [dependencies] eframe = { version = "0.31", default-features = false, features = ["default_fonts", "wayland", "x11", "glow"] } egui = "0.31" +k-launcher-config = { path = "../k-launcher-config" } k-launcher-kernel = { path = "../k-launcher-kernel" } k-launcher-os-bridge = { path = "../k-launcher-os-bridge" } tokio = { workspace = true } diff --git a/crates/k-launcher-ui-egui/src/app.rs b/crates/k-launcher-ui-egui/src/app.rs index 2756293..6c80901 100644 --- a/crates/k-launcher-ui-egui/src/app.rs +++ b/crates/k-launcher-ui-egui/src/app.rs @@ -160,7 +160,7 @@ pub fn run( engine: Arc, launcher: Arc, ) -> Result<(), eframe::Error> { - let wc = WindowConfig::launcher(); + let wc = WindowConfig::from_cfg(&k_launcher_config::WindowCfg::default()); let rt = tokio::runtime::Runtime::new().expect("tokio runtime"); let handle = rt.handle().clone(); diff --git a/crates/k-launcher-ui/Cargo.toml b/crates/k-launcher-ui/Cargo.toml index 4486257..21dbb72 100644 --- a/crates/k-launcher-ui/Cargo.toml +++ b/crates/k-launcher-ui/Cargo.toml @@ -9,6 +9,7 @@ path = "src/lib.rs" [dependencies] iced = { workspace = true } +k-launcher-config = { path = "../k-launcher-config" } k-launcher-kernel = { path = "../k-launcher-kernel" } k-launcher-os-bridge = { path = "../k-launcher-os-bridge" } tokio = { workspace = true } diff --git a/crates/k-launcher-ui/src/app.rs b/crates/k-launcher-ui/src/app.rs index 5a7bd2f..4107e99 100644 --- a/crates/k-launcher-ui/src/app.rs +++ b/crates/k-launcher-ui/src/app.rs @@ -8,30 +8,39 @@ use iced::{ window, }; +use k_launcher_config::AppearanceCfg; use k_launcher_kernel::{AppLauncher, SearchEngine, SearchResult}; use k_launcher_os_bridge::WindowConfig; -use crate::theme; - static INPUT_ID: std::sync::LazyLock = std::sync::LazyLock::new(|| iced::widget::Id::new("search")); +fn rgba(c: &[f32; 4]) -> Color { + Color::from_rgba8(c[0] as u8, c[1] as u8, c[2] as u8, c[3]) +} + pub struct KLauncherApp { engine: Arc, launcher: Arc, query: String, results: Arc>, selected: usize, + cfg: AppearanceCfg, } impl KLauncherApp { - fn new(engine: Arc, launcher: Arc) -> Self { + fn new( + engine: Arc, + launcher: Arc, + cfg: AppearanceCfg, + ) -> Self { Self { engine, launcher, query: String::new(), results: Arc::new(vec![]), selected: 0, + cfg, } } } @@ -96,13 +105,18 @@ fn update(state: &mut KLauncherApp, message: Message) -> Task { } fn view(state: &KLauncherApp) -> Element<'_, Message> { - let colors = &*theme::AERO; + let cfg = &state.cfg; + let border_color = rgba(&cfg.border_rgba); - let search_bar = text_input("Search...", &state.query) + let search_bar = text_input(&cfg.placeholder, &state.query) .id(INPUT_ID.clone()) .on_input(Message::QueryChanged) .padding(12) - .size(18); + .size(cfg.search_font_size); + + let row_radius: f32 = cfg.row_radius; + let title_size: f32 = cfg.title_size; + let desc_size: f32 = cfg.desc_size; let result_rows: Vec> = state .results @@ -111,7 +125,7 @@ fn view(state: &KLauncherApp) -> Element<'_, Message> { .map(|(i, result)| { let is_selected = i == state.selected; let bg_color = if is_selected { - colors.border_cyan + border_color } else { Color::from_rgba8(255, 255, 255, 0.07) }; @@ -124,12 +138,12 @@ fn view(state: &KLauncherApp) -> Element<'_, Message> { }; let title_col: Element<'_, Message> = if let Some(desc) = &result.description { column![ - text(result.title.as_str()).size(15), - text(desc).size(12).color(Color::from_rgba8(210, 215, 230, 1.0)), + text(result.title.as_str()).size(title_size), + text(desc).size(desc_size).color(Color::from_rgba8(210, 215, 230, 1.0)), ] .into() } else { - text(result.title.as_str()).size(15).into() + text(result.title.as_str()).size(title_size).into() }; container( row![icon_el, title_col] @@ -143,7 +157,7 @@ fn view(state: &KLauncherApp) -> Element<'_, Message> { border: Border { color: Color::TRANSPARENT, width: 0.0, - radius: 4.0.into(), + radius: row_radius.into(), }, ..Default::default() }) @@ -155,7 +169,7 @@ fn view(state: &KLauncherApp) -> Element<'_, Message> { scrollable( container( text("No results") - .size(15) + .size(title_size) .color(Color::from_rgba8(180, 180, 200, 0.5)), ) .width(Length::Fill) @@ -173,17 +187,19 @@ fn view(state: &KLauncherApp) -> Element<'_, Message> { .width(Length::Fill) .height(Length::Fill); + let bg_color = rgba(&cfg.background_rgba); + let border_width = cfg.border_width; + let border_radius = cfg.border_radius; + container(content) .width(Length::Fill) .height(Length::Fill) - .style(|_theme| container::Style { - background: Some(iced::Background::Color(Color::from_rgba8( - 20, 20, 30, 0.9, - ))), + .style(move |_theme| container::Style { + background: Some(iced::Background::Color(bg_color)), border: Border { - color: theme::AERO.border_cyan, - width: 1.0, - radius: 8.0.into(), + color: border_color, + width: border_width, + radius: border_radius.into(), }, ..Default::default() }) @@ -197,11 +213,16 @@ fn subscription(_state: &KLauncherApp) -> Subscription { }) } -pub fn run(engine: Arc, launcher: Arc) -> iced::Result { - let wc = WindowConfig::launcher(); +pub fn run( + engine: Arc, + launcher: Arc, + window_cfg: &k_launcher_config::WindowCfg, + appearance_cfg: AppearanceCfg, +) -> iced::Result { + let wc = WindowConfig::from_cfg(window_cfg); iced::application( move || { - let app = KLauncherApp::new(engine.clone(), launcher.clone()); + let app = KLauncherApp::new(engine.clone(), launcher.clone(), appearance_cfg.clone()); let focus = iced::widget::operation::focus(INPUT_ID.clone()); (app, focus) }, diff --git a/crates/k-launcher-ui/src/lib.rs b/crates/k-launcher-ui/src/lib.rs index aea8bbc..82895e1 100644 --- a/crates/k-launcher-ui/src/lib.rs +++ b/crates/k-launcher-ui/src/lib.rs @@ -3,8 +3,14 @@ pub mod theme; use std::sync::Arc; +use k_launcher_config::{AppearanceCfg, WindowCfg}; use k_launcher_kernel::{AppLauncher, SearchEngine}; -pub fn run(engine: Arc, launcher: Arc) -> iced::Result { - app::run(engine, launcher) +pub fn run( + engine: Arc, + launcher: Arc, + window_cfg: &WindowCfg, + appearance_cfg: AppearanceCfg, +) -> iced::Result { + app::run(engine, launcher, window_cfg, appearance_cfg) } diff --git a/crates/k-launcher/Cargo.toml b/crates/k-launcher/Cargo.toml index caf96eb..f3d2578 100644 --- a/crates/k-launcher/Cargo.toml +++ b/crates/k-launcher/Cargo.toml @@ -14,6 +14,7 @@ path = "src/main_egui.rs" [dependencies] iced = { workspace = true } +k-launcher-config = { path = "../k-launcher-config" } k-launcher-kernel = { path = "../k-launcher-kernel" } k-launcher-os-bridge = { path = "../k-launcher-os-bridge" } k-launcher-ui = { path = "../k-launcher-ui" } diff --git a/crates/k-launcher/src/main.rs b/crates/k-launcher/src/main.rs index 2c8379b..abad775 100644 --- a/crates/k-launcher/src/main.rs +++ b/crates/k-launcher/src/main.rs @@ -10,13 +10,20 @@ use plugin_cmd::CmdPlugin; use plugin_files::FilesPlugin; fn main() -> iced::Result { + let cfg = k_launcher_config::load(); let launcher = Arc::new(UnixAppLauncher::new()); let frecency = FrecencyStore::load(); - let kernel: Arc = Arc::new(Kernel::new(vec![ - Arc::new(CmdPlugin::new()), - Arc::new(CalcPlugin::new()), - Arc::new(FilesPlugin::new()), - Arc::new(AppsPlugin::new(FsDesktopEntrySource::new(), frecency)), - ])); - k_launcher_ui::run(kernel, launcher) + + let mut plugins: Vec> = vec![]; + if cfg.plugins.cmd { plugins.push(Arc::new(CmdPlugin::new())); } + if cfg.plugins.calc { plugins.push(Arc::new(CalcPlugin::new())); } + if cfg.plugins.files { plugins.push(Arc::new(FilesPlugin::new())); } + if cfg.plugins.apps { + plugins.push(Arc::new(AppsPlugin::new(FsDesktopEntrySource::new(), frecency))); + } + + let kernel: Arc = + Arc::new(Kernel::new(plugins, cfg.search.max_results)); + + k_launcher_ui::run(kernel, launcher, &cfg.window, cfg.appearance) } diff --git a/crates/k-launcher/src/main_egui.rs b/crates/k-launcher/src/main_egui.rs index b27f458..05219ad 100644 --- a/crates/k-launcher/src/main_egui.rs +++ b/crates/k-launcher/src/main_egui.rs @@ -17,7 +17,7 @@ fn main() -> Result<(), Box> { Arc::new(CalcPlugin::new()), Arc::new(FilesPlugin::new()), Arc::new(AppsPlugin::new(FsDesktopEntrySource::new(), frecency)), - ])); + ], 8)); k_launcher_ui_egui::run(kernel, launcher)?; Ok(()) }