mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-04-25 01:58:51 +02:00
feat(bar): add first pass at configuration loader
This commit is contained in:
82
Cargo.lock
generated
82
Cargo.lock
generated
@@ -2121,7 +2121,7 @@ checksum = "9c08c1f623a8d0b722b8b99f821eb0ba672a1618f0d3b16ddbee1cedd2dd8557"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"gpu-descriptor-types",
|
"gpu-descriptor-types",
|
||||||
"hashbrown",
|
"hashbrown 0.14.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2145,7 +2145,7 @@ dependencies = [
|
|||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"http",
|
"http",
|
||||||
"indexmap",
|
"indexmap 2.2.6",
|
||||||
"slab",
|
"slab",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
@@ -2162,6 +2162,12 @@ dependencies = [
|
|||||||
"crunchy",
|
"crunchy",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.5"
|
version = "0.14.5"
|
||||||
@@ -2450,6 +2456,16 @@ version = "0.3.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"hashbrown 0.12.3",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.2.6"
|
version = "2.2.6"
|
||||||
@@ -2457,7 +2473,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown 0.14.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2639,7 +2655,7 @@ dependencies = [
|
|||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json_lenient",
|
"serde_json_lenient",
|
||||||
"serde_yaml",
|
"serde_yaml 0.9.34+deprecated",
|
||||||
"shadow-rs",
|
"shadow-rs",
|
||||||
"strum",
|
"strum",
|
||||||
"sysinfo 0.30.13",
|
"sysinfo 0.30.13",
|
||||||
@@ -2661,17 +2677,22 @@ dependencies = [
|
|||||||
name = "komorebi-bar"
|
name = "komorebi-bar"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
|
||||||
"catppuccin-egui",
|
"catppuccin-egui",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"clap",
|
||||||
|
"color-eyre",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
|
"dirs",
|
||||||
"eframe",
|
"eframe",
|
||||||
"egui-phosphor",
|
"egui-phosphor",
|
||||||
"font-loader",
|
"font-loader",
|
||||||
"image",
|
"image",
|
||||||
"komorebi-client",
|
"komorebi-client",
|
||||||
"netdev",
|
"netdev",
|
||||||
"serde_json",
|
"schemars",
|
||||||
|
"serde",
|
||||||
|
"serde_json_lenient",
|
||||||
|
"serde_yaml 0.8.26",
|
||||||
"starship-battery",
|
"starship-battery",
|
||||||
"sysinfo 0.31.3",
|
"sysinfo 0.31.3",
|
||||||
"windows 0.54.0",
|
"windows 0.54.0",
|
||||||
@@ -2717,7 +2738,7 @@ dependencies = [
|
|||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json_lenient",
|
"serde_json_lenient",
|
||||||
"serde_yaml",
|
"serde_yaml 0.9.34+deprecated",
|
||||||
"shadow-rs",
|
"shadow-rs",
|
||||||
"sysinfo 0.30.13",
|
"sysinfo 0.30.13",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@@ -2851,6 +2872,12 @@ dependencies = [
|
|||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linked-hash-map"
|
||||||
|
version = "0.5.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
@@ -3079,7 +3106,7 @@ dependencies = [
|
|||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"codespan-reporting",
|
"codespan-reporting",
|
||||||
"hexf-parse",
|
"hexf-parse",
|
||||||
"indexmap",
|
"indexmap 2.2.6",
|
||||||
"log",
|
"log",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
@@ -3746,7 +3773,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
|
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fixedbitset",
|
"fixedbitset",
|
||||||
"indexmap",
|
"indexmap 2.2.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3805,7 +3832,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016"
|
checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"indexmap",
|
"indexmap 2.2.6",
|
||||||
"quick-xml 0.32.0",
|
"quick-xml 0.32.0",
|
||||||
"serde",
|
"serde",
|
||||||
"time",
|
"time",
|
||||||
@@ -4539,13 +4566,25 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_yaml"
|
||||||
|
version = "0.8.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap 1.9.3",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
"yaml-rust",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_yaml"
|
name = "serde_yaml"
|
||||||
version = "0.9.34+deprecated"
|
version = "0.9.34+deprecated"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap 2.2.6",
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -4586,9 +4625,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shadow-rs"
|
name = "shadow-rs"
|
||||||
version = "0.29.0"
|
version = "0.34.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0a600f795d0894cda22235b44eea4b85c2a35b405f65523645ac8e35b306817a"
|
checksum = "69fe0bac8a8752586a618a1c80d01d8ca5d40fce4f6077fbc851e48dcbdb90df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const_format",
|
"const_format",
|
||||||
"git2",
|
"git2",
|
||||||
@@ -5188,7 +5227,7 @@ version = "0.19.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap 2.2.6",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
"winnow 0.5.40",
|
"winnow 0.5.40",
|
||||||
]
|
]
|
||||||
@@ -5199,7 +5238,7 @@ version = "0.21.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
|
checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap 2.2.6",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
"winnow 0.5.40",
|
"winnow 0.5.40",
|
||||||
]
|
]
|
||||||
@@ -5210,7 +5249,7 @@ version = "0.22.16"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788"
|
checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap 2.2.6",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
@@ -5809,7 +5848,7 @@ dependencies = [
|
|||||||
"cfg_aliases 0.1.1",
|
"cfg_aliases 0.1.1",
|
||||||
"codespan-reporting",
|
"codespan-reporting",
|
||||||
"document-features",
|
"document-features",
|
||||||
"indexmap",
|
"indexmap 2.2.6",
|
||||||
"log",
|
"log",
|
||||||
"naga",
|
"naga",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -6495,6 +6534,15 @@ version = "0.8.20"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193"
|
checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yaml-rust"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||||
|
dependencies = [
|
||||||
|
"linked-hash-map",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zbus"
|
name = "zbus"
|
||||||
version = "3.15.2"
|
version = "3.15.2"
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ members = [
|
|||||||
color-eyre = "0.6"
|
color-eyre = "0.6"
|
||||||
dirs = "5"
|
dirs = "5"
|
||||||
dunce = "1"
|
dunce = "1"
|
||||||
|
schemars = "0.8"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = { package = "serde_json_lenient", version = "0.2" }
|
serde_json = { package = "serde_json_lenient", version = "0.2" }
|
||||||
serde_yaml = "0.9"
|
serde_yaml = "0.9"
|
||||||
@@ -22,7 +23,7 @@ uds_windows = "1"
|
|||||||
win32-display-data = { git = "https://github.com/LGUG2Z/win32-display-data", rev = "32a45cebf132c3d651ee22c0c40033a6b7edc945" }
|
win32-display-data = { git = "https://github.com/LGUG2Z/win32-display-data", rev = "32a45cebf132c3d651ee22c0c40033a6b7edc945" }
|
||||||
windows-implement = { version = "0.53" }
|
windows-implement = { version = "0.53" }
|
||||||
windows-interface = { version = "0.53" }
|
windows-interface = { version = "0.53" }
|
||||||
shadow-rs = "0.29"
|
shadow-rs = "0.34"
|
||||||
|
|
||||||
[workspace.dependencies.windows]
|
[workspace.dependencies.windows]
|
||||||
version = "0.54"
|
version = "0.54"
|
||||||
|
|||||||
@@ -8,17 +8,22 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
komorebi-client = { path = "../komorebi-client" }
|
komorebi-client = { path = "../komorebi-client" }
|
||||||
|
|
||||||
anyhow = "1"
|
|
||||||
catppuccin-egui = { version = "5.1", default-features = false, features = ["egui28"] }
|
catppuccin-egui = { version = "5.1", default-features = false, features = ["egui28"] }
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
|
color-eyre = "0.6"
|
||||||
crossbeam-channel = "0.5"
|
crossbeam-channel = "0.5"
|
||||||
|
dirs = { workspace = true }
|
||||||
eframe = "0.28"
|
eframe = "0.28"
|
||||||
|
egui-phosphor = "0.6.0"
|
||||||
font-loader = "0.11"
|
font-loader = "0.11"
|
||||||
image = "0.25"
|
image = "0.25"
|
||||||
netdev = "0.30"
|
netdev = "0.30"
|
||||||
serde_json = "1"
|
schemars = { workspace = true }
|
||||||
|
serde = { workspace = true }
|
||||||
|
serde_json = { workspace = true }
|
||||||
|
serde_yaml = "0.8"
|
||||||
starship-battery = "0.10"
|
starship-battery = "0.10"
|
||||||
sysinfo = "0.31"
|
sysinfo = "0.31"
|
||||||
windows = { workspace = true }
|
windows = { workspace = true }
|
||||||
windows-icons = "0.1"
|
windows-icons = "0.1"
|
||||||
egui-phosphor = "0.6.0"
|
clap = { version = "4", features = ["derive", "wrap_help"] }
|
||||||
|
|||||||
184
komorebi-bar/src/bar.rs
Normal file
184
komorebi-bar/src/bar.rs
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
use crate::config::KomobarConfig;
|
||||||
|
use crate::config::Theme;
|
||||||
|
use crate::komorebi::Komorebi;
|
||||||
|
use crate::komorebi::KomorebiNotificationState;
|
||||||
|
use crate::widget::BarWidget;
|
||||||
|
use crate::widget::WidgetConfig;
|
||||||
|
use crossbeam_channel::Receiver;
|
||||||
|
use eframe::egui::Align;
|
||||||
|
use eframe::egui::CentralPanel;
|
||||||
|
use eframe::egui::Context;
|
||||||
|
use eframe::egui::FontData;
|
||||||
|
use eframe::egui::FontDefinitions;
|
||||||
|
use eframe::egui::FontFamily;
|
||||||
|
use eframe::egui::Frame;
|
||||||
|
use eframe::egui::Layout;
|
||||||
|
use eframe::egui::Margin;
|
||||||
|
use font_loader::system_fonts;
|
||||||
|
use font_loader::system_fonts::FontPropertyBuilder;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct Komobar {
|
||||||
|
pub config: KomobarConfig,
|
||||||
|
pub komorebi_notification_state: Option<Rc<RefCell<KomorebiNotificationState>>>,
|
||||||
|
pub left_widgets: Vec<Box<dyn BarWidget>>,
|
||||||
|
pub right_widgets: Vec<Box<dyn BarWidget>>,
|
||||||
|
pub rx_gui: Receiver<komorebi_client::Notification>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Komobar {
|
||||||
|
pub fn new(
|
||||||
|
cc: &eframe::CreationContext<'_>,
|
||||||
|
rx_gui: Receiver<komorebi_client::Notification>,
|
||||||
|
config: Arc<KomobarConfig>,
|
||||||
|
) -> Self {
|
||||||
|
if let Some(font_family) = &config.font_family {
|
||||||
|
Self::add_custom_font(&cc.egui_ctx, font_family);
|
||||||
|
}
|
||||||
|
|
||||||
|
match config.theme {
|
||||||
|
Some(Theme::CatppuccinFrappe) => {
|
||||||
|
catppuccin_egui::set_theme(&cc.egui_ctx, catppuccin_egui::FRAPPE);
|
||||||
|
}
|
||||||
|
Some(Theme::CatppuccinMacchiato) => {
|
||||||
|
catppuccin_egui::set_theme(&cc.egui_ctx, catppuccin_egui::MACCHIATO);
|
||||||
|
}
|
||||||
|
Some(Theme::CatppuccinMocha) => {
|
||||||
|
catppuccin_egui::set_theme(&cc.egui_ctx, catppuccin_egui::MOCHA);
|
||||||
|
}
|
||||||
|
Some(Theme::Default) | None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut komorebi_widget = None;
|
||||||
|
let mut komorebi_widget_idx = None;
|
||||||
|
let mut komorebi_notification_state = None;
|
||||||
|
let mut side = None;
|
||||||
|
|
||||||
|
for (idx, widget_config) in config.left_widgets.iter().enumerate() {
|
||||||
|
if let WidgetConfig::Komorebi(config) = widget_config {
|
||||||
|
komorebi_widget = Some(Komorebi::from(*config));
|
||||||
|
komorebi_widget_idx = Some(idx);
|
||||||
|
side = Some(Side::Left);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (idx, widget_config) in config.right_widgets.iter().enumerate() {
|
||||||
|
if let WidgetConfig::Komorebi(config) = widget_config {
|
||||||
|
komorebi_widget = Some(Komorebi::from(*config));
|
||||||
|
komorebi_widget_idx = Some(idx);
|
||||||
|
side = Some(Side::Right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut left_widgets = config
|
||||||
|
.left_widgets
|
||||||
|
.iter()
|
||||||
|
.map(|config| config.as_boxed_bar_widget())
|
||||||
|
.collect::<Vec<Box<dyn BarWidget>>>();
|
||||||
|
|
||||||
|
let mut right_widgets = config
|
||||||
|
.right_widgets
|
||||||
|
.iter()
|
||||||
|
.map(|config| config.as_boxed_bar_widget())
|
||||||
|
.collect::<Vec<Box<dyn BarWidget>>>();
|
||||||
|
|
||||||
|
if let (Some(idx), Some(widget), Some(side)) = (komorebi_widget_idx, komorebi_widget, side)
|
||||||
|
{
|
||||||
|
komorebi_notification_state = Some(widget.komorebi_notification_state.clone());
|
||||||
|
let boxed: Box<dyn BarWidget> = Box::new(widget);
|
||||||
|
match side {
|
||||||
|
Side::Left => left_widgets[idx] = boxed,
|
||||||
|
Side::Right => right_widgets[idx] = boxed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
right_widgets.reverse();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
config: config.deref().clone(),
|
||||||
|
komorebi_notification_state,
|
||||||
|
left_widgets,
|
||||||
|
right_widgets,
|
||||||
|
rx_gui,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_custom_font(ctx: &Context, name: &str) {
|
||||||
|
let mut fonts = FontDefinitions::default();
|
||||||
|
egui_phosphor::add_to_fonts(&mut fonts, egui_phosphor::Variant::Regular);
|
||||||
|
|
||||||
|
let property = FontPropertyBuilder::new().family(name).build();
|
||||||
|
|
||||||
|
if let Some((font, _)) = system_fonts::get(&property) {
|
||||||
|
fonts
|
||||||
|
.font_data
|
||||||
|
.insert(name.to_owned(), FontData::from_owned(font));
|
||||||
|
|
||||||
|
fonts
|
||||||
|
.families
|
||||||
|
.entry(FontFamily::Proportional)
|
||||||
|
.or_default()
|
||||||
|
.insert(0, name.to_owned());
|
||||||
|
|
||||||
|
fonts
|
||||||
|
.families
|
||||||
|
.entry(FontFamily::Monospace)
|
||||||
|
.or_default()
|
||||||
|
.push(name.to_owned());
|
||||||
|
|
||||||
|
// Tell egui to use these fonts:
|
||||||
|
ctx.set_fonts(fonts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl eframe::App for Komobar {
|
||||||
|
// TODO: I think this is needed for transparency??
|
||||||
|
// fn clear_color(&self, _visuals: &Visuals) -> [f32; 4] {
|
||||||
|
// egui::Rgba::TRANSPARENT.to_array()
|
||||||
|
// let mut background = Color32::from_gray(18).to_normalized_gamma_f32();
|
||||||
|
// background[3] = 0.9;
|
||||||
|
// background
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) {
|
||||||
|
if let Some(komorebi_notification_state) = &self.komorebi_notification_state {
|
||||||
|
komorebi_notification_state
|
||||||
|
.borrow_mut()
|
||||||
|
.handle_notification(self.config.monitor.index, self.rx_gui.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let frame = if let Some(frame) = &self.config.frame {
|
||||||
|
Frame::none().outer_margin(Margin::symmetric(
|
||||||
|
frame.outer_margin.x,
|
||||||
|
frame.outer_margin.y,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Frame::none()
|
||||||
|
};
|
||||||
|
|
||||||
|
CentralPanel::default().frame(frame).show(ctx, |ui| {
|
||||||
|
ui.horizontal_centered(|ui| {
|
||||||
|
ui.with_layout(Layout::left_to_right(Align::Center), |ui| {
|
||||||
|
for w in &mut self.left_widgets {
|
||||||
|
w.render(ctx, ui);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
|
||||||
|
for w in &mut self.right_widgets {
|
||||||
|
w.render(ctx, ui);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
enum Side {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
@@ -1,16 +1,21 @@
|
|||||||
use crate::widget::BarWidget;
|
use crate::widget::BarWidget;
|
||||||
|
use crate::WIDGET_SPACING;
|
||||||
use eframe::egui::Context;
|
use eframe::egui::Context;
|
||||||
use eframe::egui::Label;
|
use eframe::egui::Label;
|
||||||
use eframe::egui::Sense;
|
use eframe::egui::Sense;
|
||||||
use eframe::egui::Ui;
|
use eframe::egui::Ui;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde::Serialize;
|
||||||
use starship_battery::units::ratio::percent;
|
use starship_battery::units::ratio::percent;
|
||||||
use starship_battery::Manager;
|
use starship_battery::Manager;
|
||||||
use starship_battery::State;
|
use starship_battery::State;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct BatteryConfig {
|
pub struct BatteryConfig {
|
||||||
|
/// Enable the Battery widget
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +107,7 @@ impl BarWidget for Battery {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.add_space(10.0);
|
ui.add_space(WIDGET_SPACING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
106
komorebi-bar/src/config.rs
Normal file
106
komorebi-bar/src/config.rs
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
use crate::widget::WidgetConfig;
|
||||||
|
use eframe::egui::Pos2;
|
||||||
|
use eframe::egui::TextBuffer;
|
||||||
|
use eframe::egui::Vec2;
|
||||||
|
use komorebi_client::Rect;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde::Serialize;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
|
pub struct KomobarConfig {
|
||||||
|
/// Viewport options (see: https://docs.rs/egui/latest/egui/viewport/struct.ViewportBuilder.html)
|
||||||
|
pub viewport: Option<ViewportConfig>,
|
||||||
|
/// Frame options (see: https://docs.rs/egui/latest/egui/containers/struct.Frame.html)
|
||||||
|
pub frame: Option<FrameConfig>,
|
||||||
|
/// Monitor options
|
||||||
|
pub monitor: MonitorConfig,
|
||||||
|
/// Font family
|
||||||
|
pub font_family: Option<String>,
|
||||||
|
/// Theme
|
||||||
|
pub theme: Option<Theme>,
|
||||||
|
/// Left side widgets (ordered left-to-right)
|
||||||
|
pub left_widgets: Vec<WidgetConfig>,
|
||||||
|
/// Right side widgets (ordered left-to-right)
|
||||||
|
pub right_widgets: Vec<WidgetConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
|
pub struct ViewportConfig {
|
||||||
|
/// The desired starting position of the bar (0,0 = top left of the screen)
|
||||||
|
pub position: Option<Position>,
|
||||||
|
/// The desired size of the bar from the starting position (usually monitor width x desired height)
|
||||||
|
pub inner_size: Option<Position>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
|
pub struct FrameConfig {
|
||||||
|
/// Margin outside the painted frame
|
||||||
|
pub outer_margin: Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
|
pub struct MonitorConfig {
|
||||||
|
/// Komorebi monitor index of the monitor on which to render the bar
|
||||||
|
pub index: usize,
|
||||||
|
/// Automatically apply a work area offset for this monitor to accommodate the bar
|
||||||
|
pub work_area_offset: Option<Rect>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KomobarConfig {
|
||||||
|
pub fn read(path: &PathBuf) -> color_eyre::Result<Self> {
|
||||||
|
let content = std::fs::read_to_string(path)?;
|
||||||
|
let mut value: Self = match path.extension().unwrap().to_string_lossy().as_str() {
|
||||||
|
"yaml" => serde_yaml::from_str(&content)?,
|
||||||
|
"json" => serde_json::from_str(&content)?,
|
||||||
|
_ => panic!("unsupported format"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if value.frame.is_none() {
|
||||||
|
value.frame = Some(FrameConfig {
|
||||||
|
outer_margin: Position { x: 10.0, y: 10.0 },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
|
pub struct Position {
|
||||||
|
/// X coordinate
|
||||||
|
pub x: f32,
|
||||||
|
/// Y coordinate
|
||||||
|
pub y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Position> for Vec2 {
|
||||||
|
fn from(value: Position) -> Self {
|
||||||
|
Self {
|
||||||
|
x: value.x,
|
||||||
|
y: value.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Position> for Pos2 {
|
||||||
|
fn from(value: Position) -> Self {
|
||||||
|
Self {
|
||||||
|
x: value.x,
|
||||||
|
y: value.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
|
pub enum Theme {
|
||||||
|
/// Default egui theme
|
||||||
|
Default,
|
||||||
|
/// Catpuccin Frappe
|
||||||
|
CatppuccinFrappe,
|
||||||
|
/// Catpuccin Macchiato
|
||||||
|
CatppuccinMacchiato,
|
||||||
|
/// Catpuccin Mocha
|
||||||
|
CatppuccinMocha,
|
||||||
|
}
|
||||||
@@ -1,12 +1,18 @@
|
|||||||
use crate::widget::BarWidget;
|
use crate::widget::BarWidget;
|
||||||
|
use crate::WIDGET_SPACING;
|
||||||
use eframe::egui::Context;
|
use eframe::egui::Context;
|
||||||
use eframe::egui::Label;
|
use eframe::egui::Label;
|
||||||
use eframe::egui::Sense;
|
use eframe::egui::Sense;
|
||||||
use eframe::egui::Ui;
|
use eframe::egui::Ui;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct DateConfig {
|
pub struct DateConfig {
|
||||||
|
/// Enable the Date widget
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
|
/// Set the Date format
|
||||||
pub format: DateFormat,
|
pub format: DateFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,12 +25,18 @@ impl From<DateConfig> for Date {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
pub enum DateFormat {
|
pub enum DateFormat {
|
||||||
|
/// Month/Date/Year format (09/08/24)
|
||||||
MonthDateYear,
|
MonthDateYear,
|
||||||
|
/// Year-Month-Date format (2024-09-08)
|
||||||
YearMonthDate,
|
YearMonthDate,
|
||||||
|
/// Date-Month-Year format (8-Sep-2024)
|
||||||
DateMonthYear,
|
DateMonthYear,
|
||||||
|
/// Day Date Month Year format (8 September 2024)
|
||||||
DayDateMonthYear,
|
DayDateMonthYear,
|
||||||
|
/// Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html)
|
||||||
|
Custom(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DateFormat {
|
impl DateFormat {
|
||||||
@@ -34,6 +46,7 @@ impl DateFormat {
|
|||||||
DateFormat::YearMonthDate => *self = Self::DateMonthYear,
|
DateFormat::YearMonthDate => *self = Self::DateMonthYear,
|
||||||
DateFormat::DateMonthYear => *self = Self::DayDateMonthYear,
|
DateFormat::DateMonthYear => *self = Self::DayDateMonthYear,
|
||||||
DateFormat::DayDateMonthYear => *self = Self::MonthDateYear,
|
DateFormat::DayDateMonthYear => *self = Self::MonthDateYear,
|
||||||
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,11 +56,12 @@ impl DateFormat {
|
|||||||
DateFormat::YearMonthDate => String::from("%F"),
|
DateFormat::YearMonthDate => String::from("%F"),
|
||||||
DateFormat::DateMonthYear => String::from("%v"),
|
DateFormat::DateMonthYear => String::from("%v"),
|
||||||
DateFormat::DayDateMonthYear => String::from("%A %e %B %Y"),
|
DateFormat::DayDateMonthYear => String::from("%A %e %B %Y"),
|
||||||
|
DateFormat::Custom(custom) => custom.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Date {
|
pub struct Date {
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
pub format: DateFormat,
|
pub format: DateFormat,
|
||||||
@@ -82,7 +96,7 @@ impl BarWidget for Date {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make spacing configurable
|
// TODO: make spacing configurable
|
||||||
ui.add_space(10.0);
|
ui.add_space(WIDGET_SPACING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,59 @@
|
|||||||
use crate::img_to_texture;
|
|
||||||
use crate::widget::BarWidget;
|
use crate::widget::BarWidget;
|
||||||
use crate::KomorebiNotificationState;
|
use crate::WIDGET_SPACING;
|
||||||
|
use crossbeam_channel::Receiver;
|
||||||
|
use eframe::egui::ColorImage;
|
||||||
use eframe::egui::Context;
|
use eframe::egui::Context;
|
||||||
use eframe::egui::Image;
|
use eframe::egui::Image;
|
||||||
use eframe::egui::Label;
|
use eframe::egui::Label;
|
||||||
use eframe::egui::SelectableLabel;
|
use eframe::egui::SelectableLabel;
|
||||||
use eframe::egui::Sense;
|
use eframe::egui::Sense;
|
||||||
|
use eframe::egui::TextureHandle;
|
||||||
|
use eframe::egui::TextureOptions;
|
||||||
use eframe::egui::Ui;
|
use eframe::egui::Ui;
|
||||||
|
use image::RgbaImage;
|
||||||
use komorebi_client::CycleDirection;
|
use komorebi_client::CycleDirection;
|
||||||
use komorebi_client::SocketMessage;
|
use komorebi_client::SocketMessage;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde::Serialize;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct KomorebiConfig {
|
pub struct KomorebiConfig {
|
||||||
pub enable: bool,
|
/// Configure the Workspaces widget
|
||||||
pub monitor_index: usize,
|
|
||||||
pub workspaces: KomorebiWorkspacesConfig,
|
pub workspaces: KomorebiWorkspacesConfig,
|
||||||
|
/// Configure the Layout widget
|
||||||
pub layout: KomorebiLayoutConfig,
|
pub layout: KomorebiLayoutConfig,
|
||||||
|
/// Configure the Focused Window widget
|
||||||
pub focused_window: KomorebiFocusedWindowConfig,
|
pub focused_window: KomorebiFocusedWindowConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct KomorebiWorkspacesConfig {
|
pub struct KomorebiWorkspacesConfig {
|
||||||
|
/// Enable the Komorebi Workspaces widget
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
|
/// Hide workspaces without any windows
|
||||||
pub hide_empty_workspaces: bool,
|
pub hide_empty_workspaces: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct KomorebiLayoutConfig {
|
pub struct KomorebiLayoutConfig {
|
||||||
|
/// Enable the Komorebi Layout widget
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct KomorebiFocusedWindowConfig {
|
pub struct KomorebiFocusedWindowConfig {
|
||||||
|
/// Enable the Komorebi Focused Window widget
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
|
/// Show the icon of the currently focused window
|
||||||
pub show_icon: bool,
|
pub show_icon: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<KomorebiConfig> for Komorebi {
|
impl From<KomorebiConfig> for Komorebi {
|
||||||
fn from(value: KomorebiConfig) -> Self {
|
fn from(value: KomorebiConfig) -> Self {
|
||||||
Self {
|
Self {
|
||||||
enable: value.enable,
|
|
||||||
komorebi_notification_state: Rc::new(RefCell::new(KomorebiNotificationState {
|
komorebi_notification_state: Rc::new(RefCell::new(KomorebiNotificationState {
|
||||||
selected_workspace: String::new(),
|
selected_workspace: String::new(),
|
||||||
focused_window_title: String::new(),
|
focused_window_title: String::new(),
|
||||||
@@ -49,7 +61,6 @@ impl From<KomorebiConfig> for Komorebi {
|
|||||||
focused_window_icon: None,
|
focused_window_icon: None,
|
||||||
layout: String::new(),
|
layout: String::new(),
|
||||||
workspaces: vec![],
|
workspaces: vec![],
|
||||||
monitor_index: value.monitor_index,
|
|
||||||
hide_empty_workspaces: value.workspaces.hide_empty_workspaces,
|
hide_empty_workspaces: value.workspaces.hide_empty_workspaces,
|
||||||
})),
|
})),
|
||||||
workspaces: value.workspaces,
|
workspaces: value.workspaces,
|
||||||
@@ -61,7 +72,6 @@ impl From<KomorebiConfig> for Komorebi {
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Komorebi {
|
pub struct Komorebi {
|
||||||
pub enable: bool,
|
|
||||||
pub komorebi_notification_state: Rc<RefCell<KomorebiNotificationState>>,
|
pub komorebi_notification_state: Rc<RefCell<KomorebiNotificationState>>,
|
||||||
pub workspaces: KomorebiWorkspacesConfig,
|
pub workspaces: KomorebiWorkspacesConfig,
|
||||||
pub layout: KomorebiLayoutConfig,
|
pub layout: KomorebiLayoutConfig,
|
||||||
@@ -70,72 +80,150 @@ pub struct Komorebi {
|
|||||||
|
|
||||||
impl BarWidget for Komorebi {
|
impl BarWidget for Komorebi {
|
||||||
fn render(&mut self, ctx: &Context, ui: &mut Ui) {
|
fn render(&mut self, ctx: &Context, ui: &mut Ui) {
|
||||||
if self.enable {
|
let mut komorebi_notification_state = self.komorebi_notification_state.borrow_mut();
|
||||||
let mut komorebi_notification_state = self.komorebi_notification_state.borrow_mut();
|
|
||||||
|
if self.workspaces.enable {
|
||||||
let mut update = None;
|
let mut update = None;
|
||||||
|
|
||||||
if self.workspaces.enable {
|
for (i, ws) in komorebi_notification_state.workspaces.iter().enumerate() {
|
||||||
for (i, ws) in komorebi_notification_state.workspaces.iter().enumerate() {
|
|
||||||
if ui
|
|
||||||
.add(SelectableLabel::new(
|
|
||||||
komorebi_notification_state.selected_workspace.eq(ws),
|
|
||||||
ws.to_string(),
|
|
||||||
))
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
update = Some(ws.to_string());
|
|
||||||
komorebi_client::send_message(&SocketMessage::MouseFollowsFocus(false))
|
|
||||||
.unwrap();
|
|
||||||
komorebi_client::send_message(&SocketMessage::FocusWorkspaceNumber(i))
|
|
||||||
.unwrap();
|
|
||||||
// TODO: store MFF value from state and restore that here instead of "true"
|
|
||||||
komorebi_client::send_message(&SocketMessage::MouseFollowsFocus(true))
|
|
||||||
.unwrap();
|
|
||||||
komorebi_client::send_message(&SocketMessage::Retile).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(update) = update {
|
|
||||||
komorebi_notification_state.selected_workspace = update;
|
|
||||||
}
|
|
||||||
|
|
||||||
ui.add_space(10.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.layout.enable {
|
|
||||||
if ui
|
if ui
|
||||||
.add(
|
.add(SelectableLabel::new(
|
||||||
Label::new(&komorebi_notification_state.layout)
|
komorebi_notification_state.selected_workspace.eq(ws),
|
||||||
.selectable(false)
|
ws.to_string(),
|
||||||
.sense(Sense::click()),
|
))
|
||||||
)
|
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
komorebi_client::send_message(&SocketMessage::CycleLayout(
|
update = Some(ws.to_string());
|
||||||
CycleDirection::Next,
|
komorebi_client::send_message(&SocketMessage::MouseFollowsFocus(false))
|
||||||
))
|
.unwrap();
|
||||||
.unwrap();
|
komorebi_client::send_message(&SocketMessage::FocusWorkspaceNumber(i)).unwrap();
|
||||||
|
// TODO: store MFF value from state and restore that here instead of "true"
|
||||||
|
komorebi_client::send_message(&SocketMessage::MouseFollowsFocus(true)).unwrap();
|
||||||
|
komorebi_client::send_message(&SocketMessage::Retile).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.add_space(10.0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.focused_window.enable {
|
if let Some(update) = update {
|
||||||
if self.focused_window.show_icon {
|
komorebi_notification_state.selected_workspace = update;
|
||||||
if let Some(img) = &komorebi_notification_state.focused_window_icon {
|
}
|
||||||
ui.add(
|
|
||||||
Image::from(&img_to_texture(ctx, img))
|
ui.add_space(WIDGET_SPACING);
|
||||||
.maintain_aspect_ratio(true)
|
}
|
||||||
.max_height(15.0),
|
|
||||||
);
|
if self.layout.enable {
|
||||||
|
if ui
|
||||||
|
.add(
|
||||||
|
Label::new(&komorebi_notification_state.layout)
|
||||||
|
.selectable(false)
|
||||||
|
.sense(Sense::click()),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
komorebi_client::send_message(&SocketMessage::CycleLayout(CycleDirection::Next))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.add_space(WIDGET_SPACING);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.focused_window.enable {
|
||||||
|
if self.focused_window.show_icon {
|
||||||
|
if let Some(img) = &komorebi_notification_state.focused_window_icon {
|
||||||
|
ui.add(
|
||||||
|
Image::from(&img_to_texture(ctx, img))
|
||||||
|
.maintain_aspect_ratio(true)
|
||||||
|
.max_height(15.0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.add(Label::new(&komorebi_notification_state.focused_window_title).selectable(false));
|
||||||
|
|
||||||
|
ui.add_space(WIDGET_SPACING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn img_to_texture(ctx: &Context, rgba_image: &RgbaImage) -> TextureHandle {
|
||||||
|
let size = [rgba_image.width() as usize, rgba_image.height() as usize];
|
||||||
|
let pixels = rgba_image.as_flat_samples();
|
||||||
|
let color_image = ColorImage::from_rgba_unmultiplied(size, pixels.as_slice());
|
||||||
|
ctx.load_texture("icon", color_image, TextureOptions::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct KomorebiNotificationState {
|
||||||
|
pub workspaces: Vec<String>,
|
||||||
|
pub selected_workspace: String,
|
||||||
|
pub focused_window_title: String,
|
||||||
|
pub focused_window_pid: Option<u32>,
|
||||||
|
pub focused_window_icon: Option<RgbaImage>,
|
||||||
|
pub layout: String,
|
||||||
|
pub hide_empty_workspaces: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KomorebiNotificationState {
|
||||||
|
pub fn handle_notification(
|
||||||
|
&mut self,
|
||||||
|
monitor_index: usize,
|
||||||
|
rx_gui: Receiver<komorebi_client::Notification>,
|
||||||
|
) {
|
||||||
|
if let Ok(notification) = rx_gui.try_recv() {
|
||||||
|
let monitor = ¬ification.state.monitors.elements()[monitor_index];
|
||||||
|
let focused_workspace_idx = monitor.focused_workspace_idx();
|
||||||
|
|
||||||
|
let mut workspaces = vec![];
|
||||||
|
self.selected_workspace = monitor.workspaces()[focused_workspace_idx]
|
||||||
|
.name()
|
||||||
|
.to_owned()
|
||||||
|
.unwrap_or_else(|| format!("{}", focused_workspace_idx + 1));
|
||||||
|
|
||||||
|
for (i, ws) in monitor.workspaces().iter().enumerate() {
|
||||||
|
let should_add = if self.hide_empty_workspaces {
|
||||||
|
focused_workspace_idx == i || !ws.containers().is_empty()
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
|
if should_add {
|
||||||
|
workspaces.push(ws.name().to_owned().unwrap_or_else(|| format!("{}", i + 1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.workspaces = workspaces;
|
||||||
|
self.layout = match monitor.workspaces()[focused_workspace_idx].layout() {
|
||||||
|
komorebi_client::Layout::Default(layout) => layout.to_string(),
|
||||||
|
komorebi_client::Layout::Custom(_) => String::from("Custom"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(container) = monitor.workspaces()[focused_workspace_idx].focused_container()
|
||||||
|
{
|
||||||
|
if let Some(window) = container.focused_window() {
|
||||||
|
if let Ok(title) = window.title() {
|
||||||
|
self.focused_window_title.clone_from(&title);
|
||||||
|
self.focused_window_pid = Some(window.process_id());
|
||||||
|
let img = windows_icons::get_icon_by_process_id(window.process_id());
|
||||||
|
self.focused_window_icon = Some(img);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.focused_window_title.clear();
|
||||||
|
self.focused_window_icon = None;
|
||||||
|
}
|
||||||
|
|
||||||
ui.add(
|
if let Some(container) = monitor.workspaces()[focused_workspace_idx].monocle_container()
|
||||||
Label::new(&komorebi_notification_state.focused_window_title).selectable(false),
|
{
|
||||||
);
|
if let Some(window) = container.focused_window() {
|
||||||
|
if let Ok(title) = window.title() {
|
||||||
|
self.focused_window_title.clone_from(&title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ui.add_space(10.0);
|
if let Some(window) = monitor.workspaces()[focused_workspace_idx].maximized_window() {
|
||||||
|
if let Ok(title) = window.title() {
|
||||||
|
self.focused_window_title.clone_from(&title);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
mod bar;
|
||||||
mod battery;
|
mod battery;
|
||||||
|
mod config;
|
||||||
mod date;
|
mod date;
|
||||||
mod komorebi;
|
mod komorebi;
|
||||||
mod media;
|
mod media;
|
||||||
@@ -8,161 +10,125 @@ mod storage;
|
|||||||
mod time;
|
mod time;
|
||||||
mod widget;
|
mod widget;
|
||||||
|
|
||||||
use crate::battery::Battery;
|
use crate::bar::Komobar;
|
||||||
use crate::battery::BatteryConfig;
|
use crate::config::KomobarConfig;
|
||||||
use crate::date::Date;
|
use crate::config::Position;
|
||||||
use crate::date::DateConfig;
|
use clap::Parser;
|
||||||
use crate::date::DateFormat;
|
|
||||||
use crate::komorebi::Komorebi;
|
|
||||||
use crate::komorebi::KomorebiConfig;
|
|
||||||
use crate::komorebi::KomorebiFocusedWindowConfig;
|
|
||||||
use crate::komorebi::KomorebiLayoutConfig;
|
|
||||||
use crate::komorebi::KomorebiWorkspacesConfig;
|
|
||||||
use crate::media::Media;
|
|
||||||
use crate::media::MediaConfig;
|
|
||||||
use crate::memory::Memory;
|
|
||||||
use crate::memory::MemoryConfig;
|
|
||||||
use crate::network::Network;
|
|
||||||
use crate::network::NetworkConfig;
|
|
||||||
use crate::storage::Storage;
|
|
||||||
use crate::storage::StorageConfig;
|
|
||||||
use crate::time::TimeConfig;
|
|
||||||
use crate::time::TimeFormat;
|
|
||||||
use crate::widget::BarWidget;
|
|
||||||
use crossbeam_channel::Receiver;
|
|
||||||
use eframe::egui;
|
|
||||||
use eframe::egui::Align;
|
|
||||||
use eframe::egui::ColorImage;
|
|
||||||
use eframe::egui::Context;
|
|
||||||
use eframe::egui::Layout;
|
|
||||||
use eframe::egui::TextureHandle;
|
|
||||||
use eframe::egui::ViewportBuilder;
|
use eframe::egui::ViewportBuilder;
|
||||||
use eframe::emath::Pos2;
|
|
||||||
use eframe::emath::Vec2;
|
|
||||||
use font_loader::system_fonts;
|
|
||||||
use font_loader::system_fonts::FontPropertyBuilder;
|
|
||||||
use image::RgbaImage;
|
|
||||||
use komorebi_client::SocketMessage;
|
use komorebi_client::SocketMessage;
|
||||||
use std::cell::RefCell;
|
use schemars::gen::SchemaSettings;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::ops::Deref;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use time::Time;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
pub static WIDGET_SPACING: f32 = 10.0;
|
||||||
pub struct Position {
|
|
||||||
x: f32,
|
|
||||||
y: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Position> for Vec2 {
|
#[derive(Parser)]
|
||||||
fn from(value: Position) -> Self {
|
#[clap(author, about, version)]
|
||||||
Self {
|
struct Opts {
|
||||||
x: value.x,
|
/// Print the JSON schema of the configuration file and exit
|
||||||
y: value.y,
|
#[clap(long)]
|
||||||
}
|
schema: bool,
|
||||||
}
|
/// Path to a JSON or YAML configuration file
|
||||||
}
|
#[clap(short, long)]
|
||||||
|
config: Option<PathBuf>,
|
||||||
impl From<Position> for Pos2 {
|
|
||||||
fn from(value: Position) -> Self {
|
|
||||||
Self {
|
|
||||||
x: value.x,
|
|
||||||
y: value.y,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Config {
|
|
||||||
inner_size: Position,
|
|
||||||
position: Position,
|
|
||||||
outer_margin: Position,
|
|
||||||
monitor_index: usize,
|
|
||||||
monitor_work_area_offset: Option<komorebi_client::Rect>,
|
|
||||||
font_family: Option<String>,
|
|
||||||
time: TimeConfig,
|
|
||||||
date: DateConfig,
|
|
||||||
storage: StorageConfig,
|
|
||||||
memory: MemoryConfig,
|
|
||||||
media: MediaConfig,
|
|
||||||
battery: BatteryConfig,
|
|
||||||
network: NetworkConfig,
|
|
||||||
komorebi: KomorebiConfig,
|
|
||||||
theme: Theme,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub enum Theme {
|
|
||||||
Default,
|
|
||||||
CatppuccinFrappe,
|
|
||||||
CatppuccinMacchiato,
|
|
||||||
CatppuccinMocha,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> eframe::Result<()> {
|
fn main() -> eframe::Result<()> {
|
||||||
let config = Config {
|
let opts: Opts = Opts::parse();
|
||||||
inner_size: Position { x: 5120.0, y: 20.0 },
|
|
||||||
position: Position { x: 0.0, y: 0.0 },
|
if opts.schema {
|
||||||
outer_margin: Position { x: 10.0, y: 10.0 },
|
let settings = SchemaSettings::default().with(|s| {
|
||||||
monitor_index: 0,
|
s.option_nullable = false;
|
||||||
font_family: Some(String::from("JetBrains Mono")),
|
s.option_add_null_type = false;
|
||||||
monitor_work_area_offset: Some(komorebi_client::Rect {
|
s.inline_subschemas = true;
|
||||||
left: 0,
|
});
|
||||||
top: 40,
|
|
||||||
right: 0,
|
let gen = settings.into_generator();
|
||||||
bottom: 40,
|
let socket_message = gen.into_root_schema_for::<KomobarConfig>();
|
||||||
}),
|
let schema = serde_json::to_string_pretty(&socket_message).unwrap();
|
||||||
time: TimeConfig {
|
|
||||||
enable: true,
|
println!("{schema}");
|
||||||
format: TimeFormat::TwentyFourHour,
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let home_dir: PathBuf = std::env::var("KOMOREBI_CONFIG_HOME").map_or_else(
|
||||||
|
|_| dirs::home_dir().expect("there is no home directory"),
|
||||||
|
|home_path| {
|
||||||
|
let home = PathBuf::from(&home_path);
|
||||||
|
|
||||||
|
if home.as_path().is_dir() {
|
||||||
|
home
|
||||||
|
} else {
|
||||||
|
panic!("$Env:KOMOREBI_CONFIG_HOME is set to '{home_path}', which is not a valid directory");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
date: DateConfig {
|
);
|
||||||
enable: true,
|
|
||||||
format: DateFormat::DayDateMonthYear,
|
let config_path = opts.config.map_or_else(
|
||||||
|
|| {
|
||||||
|
let mut config = home_dir.join("komorebi.bar.json");
|
||||||
|
if !config.is_file() {
|
||||||
|
config.pop();
|
||||||
|
config.push("komorebi.bar.yaml");
|
||||||
|
}
|
||||||
|
|
||||||
|
if !config.is_file() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(config)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
storage: StorageConfig { enable: true },
|
Option::from,
|
||||||
memory: MemoryConfig { enable: true },
|
);
|
||||||
media: MediaConfig { enable: true },
|
|
||||||
battery: BatteryConfig { enable: true },
|
let config = match config_path {
|
||||||
network: NetworkConfig {
|
None => panic!(
|
||||||
enable: true,
|
"no komorebi.bar.json or komorebi.bar.yaml found in {}",
|
||||||
show_data: true,
|
home_dir.as_path().to_string_lossy()
|
||||||
},
|
),
|
||||||
komorebi: KomorebiConfig {
|
Some(config) => KomobarConfig::read(&config).unwrap(),
|
||||||
enable: true,
|
|
||||||
monitor_index: 0,
|
|
||||||
workspaces: KomorebiWorkspacesConfig {
|
|
||||||
enable: true,
|
|
||||||
hide_empty_workspaces: true,
|
|
||||||
},
|
|
||||||
layout: KomorebiLayoutConfig { enable: true },
|
|
||||||
focused_window: KomorebiFocusedWindowConfig {
|
|
||||||
enable: true,
|
|
||||||
show_icon: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
theme: Theme::CatppuccinMacchiato,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: ensure that config.monitor_index represents a valid komorebi monitor index
|
let mut builder = ViewportBuilder::default()
|
||||||
|
.with_decorations(false)
|
||||||
|
// .with_transparent(config.transparent)
|
||||||
|
.with_taskbar(false)
|
||||||
|
.with_position(Position { x: 0.0, y: 0.0 })
|
||||||
|
.with_inner_size({
|
||||||
|
let state = serde_json::from_str::<komorebi_client::State>(
|
||||||
|
&komorebi_client::send_query(&SocketMessage::State).unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Position {
|
||||||
|
x: state.monitors.elements()[config.monitor.index].size().right as f32,
|
||||||
|
y: 20.0,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(viewport) = &config.viewport {
|
||||||
|
if let Some(position) = &viewport.position {
|
||||||
|
let b = builder.clone();
|
||||||
|
builder = b.with_position(*position);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(inner_size) = &viewport.inner_size {
|
||||||
|
let b = builder.clone();
|
||||||
|
builder = b.with_inner_size(*inner_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let native_options = eframe::NativeOptions {
|
let native_options = eframe::NativeOptions {
|
||||||
viewport: ViewportBuilder::default()
|
viewport: builder,
|
||||||
.with_decorations(false)
|
|
||||||
// .with_transparent(config.transparent)
|
|
||||||
.with_position(config.position)
|
|
||||||
.with_taskbar(false)
|
|
||||||
.with_inner_size(config.inner_size),
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(rect) = &config.monitor_work_area_offset {
|
if let Some(rect) = &config.monitor.work_area_offset {
|
||||||
komorebi_client::send_message(&SocketMessage::MonitorWorkAreaOffset(
|
komorebi_client::send_message(&SocketMessage::MonitorWorkAreaOffset(
|
||||||
config.monitor_index,
|
config.monitor.index,
|
||||||
*rect,
|
*rect,
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -207,10 +173,10 @@ fn main() -> eframe::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// here we have reconnected
|
// here we have reconnected
|
||||||
if let Some(rect) = &config_cl.monitor_work_area_offset {
|
if let Some(rect) = &config_cl.monitor.work_area_offset {
|
||||||
while komorebi_client::send_message(
|
while komorebi_client::send_message(
|
||||||
&SocketMessage::MonitorWorkAreaOffset(
|
&SocketMessage::MonitorWorkAreaOffset(
|
||||||
config_cl.monitor_index,
|
config_cl.monitor.index,
|
||||||
*rect,
|
*rect,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -241,214 +207,3 @@ fn main() -> eframe::Result<()> {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Komobar {
|
|
||||||
config: Config,
|
|
||||||
komorebi_notification_state: Rc<RefCell<KomorebiNotificationState>>,
|
|
||||||
left_widgets: Vec<Box<dyn BarWidget>>,
|
|
||||||
right_widgets: Vec<Box<dyn BarWidget>>,
|
|
||||||
rx_gui: Receiver<komorebi_client::Notification>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
struct KomorebiNotificationState {
|
|
||||||
monitor_index: usize,
|
|
||||||
workspaces: Vec<String>,
|
|
||||||
selected_workspace: String,
|
|
||||||
focused_window_title: String,
|
|
||||||
focused_window_pid: Option<u32>,
|
|
||||||
focused_window_icon: Option<RgbaImage>,
|
|
||||||
layout: String,
|
|
||||||
hide_empty_workspaces: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KomorebiNotificationState {
|
|
||||||
fn handle_notification(&mut self, rx_gui: Receiver<komorebi_client::Notification>) {
|
|
||||||
if let Ok(notification) = rx_gui.try_recv() {
|
|
||||||
let monitor = ¬ification.state.monitors.elements()[self.monitor_index];
|
|
||||||
let focused_workspace_idx = monitor.focused_workspace_idx();
|
|
||||||
|
|
||||||
let mut workspaces = vec![];
|
|
||||||
self.selected_workspace = monitor.workspaces()[focused_workspace_idx]
|
|
||||||
.name()
|
|
||||||
.to_owned()
|
|
||||||
.unwrap_or_else(|| format!("{}", focused_workspace_idx + 1));
|
|
||||||
|
|
||||||
for (i, ws) in monitor.workspaces().iter().enumerate() {
|
|
||||||
let should_add = if self.hide_empty_workspaces {
|
|
||||||
focused_workspace_idx == i || !ws.containers().is_empty()
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
};
|
|
||||||
|
|
||||||
if should_add {
|
|
||||||
workspaces.push(ws.name().to_owned().unwrap_or_else(|| format!("{}", i + 1)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.workspaces = workspaces;
|
|
||||||
self.layout = match monitor.workspaces()[focused_workspace_idx].layout() {
|
|
||||||
komorebi_client::Layout::Default(layout) => layout.to_string(),
|
|
||||||
komorebi_client::Layout::Custom(_) => String::from("Custom"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(container) = monitor.workspaces()[focused_workspace_idx].focused_container()
|
|
||||||
{
|
|
||||||
if let Some(window) = container.focused_window() {
|
|
||||||
if let Ok(title) = window.title() {
|
|
||||||
self.focused_window_title.clone_from(&title);
|
|
||||||
self.focused_window_pid = Some(window.process_id());
|
|
||||||
let img = windows_icons::get_icon_by_process_id(window.process_id());
|
|
||||||
self.focused_window_icon = Some(img);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.focused_window_title.clear();
|
|
||||||
self.focused_window_icon = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(container) = monitor.workspaces()[focused_workspace_idx].monocle_container()
|
|
||||||
{
|
|
||||||
if let Some(window) = container.focused_window() {
|
|
||||||
if let Ok(title) = window.title() {
|
|
||||||
self.focused_window_title.clone_from(&title);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(window) = monitor.workspaces()[focused_workspace_idx].maximized_window() {
|
|
||||||
if let Ok(title) = window.title() {
|
|
||||||
self.focused_window_title.clone_from(&title);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_custom_font(ctx: &Context, name: &str) {
|
|
||||||
let mut fonts = egui::FontDefinitions::default();
|
|
||||||
egui_phosphor::add_to_fonts(&mut fonts, egui_phosphor::Variant::Regular);
|
|
||||||
|
|
||||||
let property = FontPropertyBuilder::new().family(name).build();
|
|
||||||
|
|
||||||
if let Some((font, _)) = system_fonts::get(&property) {
|
|
||||||
// Install my own font (maybe supporting non-latin characters).
|
|
||||||
// .ttf and .otf files supported.
|
|
||||||
fonts
|
|
||||||
.font_data
|
|
||||||
.insert(name.to_owned(), egui::FontData::from_owned(font));
|
|
||||||
|
|
||||||
// Put my font first (highest priority) for proportional text:
|
|
||||||
fonts
|
|
||||||
.families
|
|
||||||
.entry(egui::FontFamily::Proportional)
|
|
||||||
.or_default()
|
|
||||||
.insert(0, name.to_owned());
|
|
||||||
|
|
||||||
// Put my font as last fallback for monospace:
|
|
||||||
fonts
|
|
||||||
.families
|
|
||||||
.entry(egui::FontFamily::Monospace)
|
|
||||||
.or_default()
|
|
||||||
.push(name.to_owned());
|
|
||||||
|
|
||||||
// Tell egui to use these fonts:
|
|
||||||
ctx.set_fonts(fonts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Komobar {
|
|
||||||
fn new(
|
|
||||||
cc: &eframe::CreationContext<'_>,
|
|
||||||
rx: Receiver<komorebi_client::Notification>,
|
|
||||||
config: Arc<Config>,
|
|
||||||
) -> Self {
|
|
||||||
if let Some(font_family) = &config.font_family {
|
|
||||||
add_custom_font(&cc.egui_ctx, font_family);
|
|
||||||
}
|
|
||||||
|
|
||||||
match config.theme {
|
|
||||||
Theme::Default => {}
|
|
||||||
Theme::CatppuccinFrappe => {
|
|
||||||
catppuccin_egui::set_theme(&cc.egui_ctx, catppuccin_egui::FRAPPE);
|
|
||||||
}
|
|
||||||
Theme::CatppuccinMacchiato => {
|
|
||||||
catppuccin_egui::set_theme(&cc.egui_ctx, catppuccin_egui::MACCHIATO);
|
|
||||||
}
|
|
||||||
Theme::CatppuccinMocha => {
|
|
||||||
catppuccin_egui::set_theme(&cc.egui_ctx, catppuccin_egui::MOCHA);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Customize egui here with cc.egui_ctx.set_fonts and cc.egui_ctx.set_visuals.
|
|
||||||
// Restore app state using cc.storage (requires the "persistence" feature).
|
|
||||||
// Use the cc.gl (a glow::Context) to create graphics shaders and buffers that you can use
|
|
||||||
// for e.g. egui::PaintCallback.
|
|
||||||
let komorebi_workspaces = Komorebi::from(config.komorebi);
|
|
||||||
let komorebi_notification_state = komorebi_workspaces.komorebi_notification_state.clone();
|
|
||||||
|
|
||||||
let left_widgets: Vec<Box<dyn BarWidget>> = vec![Box::new(komorebi_workspaces.clone())];
|
|
||||||
|
|
||||||
let mut right_widgets: Vec<Box<dyn BarWidget>> = vec![
|
|
||||||
Box::new(Media::from(config.media)),
|
|
||||||
Box::new(Storage::from(config.storage)),
|
|
||||||
Box::new(Memory::from(config.memory)),
|
|
||||||
Box::new(Network::from(config.network)),
|
|
||||||
Box::new(Date::from(config.date)),
|
|
||||||
Box::new(Time::from(config.time)),
|
|
||||||
Box::new(Battery::from(config.battery)),
|
|
||||||
];
|
|
||||||
|
|
||||||
right_widgets.reverse();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
config: config.deref().clone(),
|
|
||||||
komorebi_notification_state,
|
|
||||||
left_widgets,
|
|
||||||
right_widgets,
|
|
||||||
rx_gui: rx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn img_to_texture(ctx: &Context, rgba_image: &RgbaImage) -> TextureHandle {
|
|
||||||
let size = [rgba_image.width() as usize, rgba_image.height() as usize];
|
|
||||||
let pixels = rgba_image.as_flat_samples();
|
|
||||||
let color_image = ColorImage::from_rgba_unmultiplied(size, pixels.as_slice());
|
|
||||||
ctx.load_texture("icon", color_image, egui::TextureOptions::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
impl eframe::App for Komobar {
|
|
||||||
// TODO: I think this is needed for transparency??
|
|
||||||
// fn clear_color(&self, _visuals: &Visuals) -> [f32; 4] {
|
|
||||||
// egui::Rgba::TRANSPARENT.to_array()
|
|
||||||
// let mut background = Color32::from_gray(18).to_normalized_gamma_f32();
|
|
||||||
// background[3] = 0.9;
|
|
||||||
// background
|
|
||||||
// }
|
|
||||||
|
|
||||||
fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) {
|
|
||||||
self.komorebi_notification_state
|
|
||||||
.borrow_mut()
|
|
||||||
.handle_notification(self.rx_gui.clone());
|
|
||||||
|
|
||||||
egui::CentralPanel::default()
|
|
||||||
.frame(egui::Frame::none().outer_margin(egui::Margin::symmetric(
|
|
||||||
self.config.outer_margin.x,
|
|
||||||
self.config.outer_margin.y,
|
|
||||||
)))
|
|
||||||
.show(ctx, |ui| {
|
|
||||||
ui.horizontal_centered(|ui| {
|
|
||||||
ui.with_layout(Layout::left_to_right(Align::Center), |ui| {
|
|
||||||
for w in &mut self.left_widgets {
|
|
||||||
w.render(ctx, ui);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
|
|
||||||
for w in &mut self.right_widgets {
|
|
||||||
w.render(ctx, ui);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
use crate::widget::BarWidget;
|
use crate::widget::BarWidget;
|
||||||
|
use crate::WIDGET_SPACING;
|
||||||
use eframe::egui::Context;
|
use eframe::egui::Context;
|
||||||
use eframe::egui::Label;
|
use eframe::egui::Label;
|
||||||
use eframe::egui::Sense;
|
use eframe::egui::Sense;
|
||||||
use eframe::egui::Ui;
|
use eframe::egui::Ui;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde::Serialize;
|
||||||
use windows::Media::Control::GlobalSystemMediaTransportControlsSessionManager;
|
use windows::Media::Control::GlobalSystemMediaTransportControlsSessionManager;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct MediaConfig {
|
pub struct MediaConfig {
|
||||||
|
/// Enable the Media widget
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +84,7 @@ impl BarWidget for Media {
|
|||||||
self.toggle();
|
self.toggle();
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.add_space(10.0);
|
ui.add_space(WIDGET_SPACING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
use crate::widget::BarWidget;
|
use crate::widget::BarWidget;
|
||||||
|
use crate::WIDGET_SPACING;
|
||||||
use eframe::egui::Context;
|
use eframe::egui::Context;
|
||||||
use eframe::egui::Label;
|
use eframe::egui::Label;
|
||||||
use eframe::egui::Sense;
|
use eframe::egui::Sense;
|
||||||
use eframe::egui::Ui;
|
use eframe::egui::Ui;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde::Serialize;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use sysinfo::RefreshKind;
|
use sysinfo::RefreshKind;
|
||||||
use sysinfo::System;
|
use sysinfo::System;
|
||||||
|
|
||||||
pub struct Memory {
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
pub enable: bool,
|
|
||||||
system: System,
|
|
||||||
last_updated: Instant,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub struct MemoryConfig {
|
pub struct MemoryConfig {
|
||||||
|
/// Enable the Memory widget
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,6 +34,12 @@ impl From<MemoryConfig> for Memory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Memory {
|
||||||
|
pub enable: bool,
|
||||||
|
system: System,
|
||||||
|
last_updated: Instant,
|
||||||
|
}
|
||||||
|
|
||||||
impl Memory {
|
impl Memory {
|
||||||
fn output(&mut self) -> Vec<String> {
|
fn output(&mut self) -> Vec<String> {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
@@ -68,7 +73,7 @@ impl BarWidget for Memory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.add_space(10.0);
|
ui.add_space(WIDGET_SPACING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
use crate::widget::BarWidget;
|
use crate::widget::BarWidget;
|
||||||
|
use crate::WIDGET_SPACING;
|
||||||
use eframe::egui::Context;
|
use eframe::egui::Context;
|
||||||
use eframe::egui::Label;
|
use eframe::egui::Label;
|
||||||
use eframe::egui::Sense;
|
use eframe::egui::Sense;
|
||||||
use eframe::egui::Ui;
|
use eframe::egui::Ui;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde::Serialize;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use sysinfo::Networks;
|
use sysinfo::Networks;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct NetworkConfig {
|
pub struct NetworkConfig {
|
||||||
|
/// Enable the Network widget
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
|
/// Show network transfer data
|
||||||
pub show_data: bool,
|
pub show_data: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +146,7 @@ impl BarWidget for Network {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.add_space(10.0);
|
ui.add_space(WIDGET_SPACING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
use crate::widget::BarWidget;
|
use crate::widget::BarWidget;
|
||||||
|
use crate::WIDGET_SPACING;
|
||||||
use eframe::egui::Context;
|
use eframe::egui::Context;
|
||||||
use eframe::egui::Label;
|
use eframe::egui::Label;
|
||||||
use eframe::egui::Sense;
|
use eframe::egui::Sense;
|
||||||
use eframe::egui::Ui;
|
use eframe::egui::Ui;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde::Serialize;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use sysinfo::Disks;
|
use sysinfo::Disks;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct StorageConfig {
|
pub struct StorageConfig {
|
||||||
|
/// Enable the Storage widget
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +92,7 @@ impl BarWidget for Storage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.add_space(10.0);
|
ui.add_space(WIDGET_SPACING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
use crate::widget::BarWidget;
|
use crate::widget::BarWidget;
|
||||||
|
use crate::WIDGET_SPACING;
|
||||||
use eframe::egui::Context;
|
use eframe::egui::Context;
|
||||||
use eframe::egui::Label;
|
use eframe::egui::Label;
|
||||||
use eframe::egui::Sense;
|
use eframe::egui::Sense;
|
||||||
use eframe::egui::Ui;
|
use eframe::egui::Ui;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct TimeConfig {
|
pub struct TimeConfig {
|
||||||
|
/// Enable the Time widget
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
|
/// Set the Time format
|
||||||
pub format: TimeFormat,
|
pub format: TimeFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,10 +25,14 @@ impl From<TimeConfig> for Time {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
pub enum TimeFormat {
|
pub enum TimeFormat {
|
||||||
|
/// Twelve-hour format (with seconds)
|
||||||
TwelveHour,
|
TwelveHour,
|
||||||
|
/// Twenty-four-hour format (with seconds)
|
||||||
TwentyFourHour,
|
TwentyFourHour,
|
||||||
|
/// Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html)
|
||||||
|
Custom(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TimeFormat {
|
impl TimeFormat {
|
||||||
@@ -30,6 +40,7 @@ impl TimeFormat {
|
|||||||
match self {
|
match self {
|
||||||
TimeFormat::TwelveHour => *self = TimeFormat::TwentyFourHour,
|
TimeFormat::TwelveHour => *self = TimeFormat::TwentyFourHour,
|
||||||
TimeFormat::TwentyFourHour => *self = TimeFormat::TwelveHour,
|
TimeFormat::TwentyFourHour => *self = TimeFormat::TwelveHour,
|
||||||
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,11 +48,12 @@ impl TimeFormat {
|
|||||||
match self {
|
match self {
|
||||||
TimeFormat::TwelveHour => String::from("%l:%M:%S %p"),
|
TimeFormat::TwelveHour => String::from("%l:%M:%S %p"),
|
||||||
TimeFormat::TwentyFourHour => String::from("%T"),
|
TimeFormat::TwentyFourHour => String::from("%T"),
|
||||||
|
TimeFormat::Custom(format) => format.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Time {
|
pub struct Time {
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
pub format: TimeFormat,
|
pub format: TimeFormat,
|
||||||
@@ -72,7 +84,7 @@ impl BarWidget for Time {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make spacing configurable
|
// TODO: make spacing configurable
|
||||||
ui.add_space(10.0);
|
ui.add_space(WIDGET_SPACING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,52 @@
|
|||||||
|
use crate::battery::Battery;
|
||||||
|
use crate::battery::BatteryConfig;
|
||||||
|
use crate::date::Date;
|
||||||
|
use crate::date::DateConfig;
|
||||||
|
use crate::komorebi::Komorebi;
|
||||||
|
use crate::komorebi::KomorebiConfig;
|
||||||
|
use crate::media::Media;
|
||||||
|
use crate::media::MediaConfig;
|
||||||
|
use crate::memory::Memory;
|
||||||
|
use crate::memory::MemoryConfig;
|
||||||
|
use crate::network::Network;
|
||||||
|
use crate::network::NetworkConfig;
|
||||||
|
use crate::storage::Storage;
|
||||||
|
use crate::storage::StorageConfig;
|
||||||
|
use crate::time::Time;
|
||||||
|
use crate::time::TimeConfig;
|
||||||
use eframe::egui::Context;
|
use eframe::egui::Context;
|
||||||
use eframe::egui::Ui;
|
use eframe::egui::Ui;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
pub trait BarWidget {
|
pub trait BarWidget {
|
||||||
fn render(&mut self, ctx: &Context, ui: &mut Ui);
|
fn render(&mut self, ctx: &Context, ui: &mut Ui);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
|
pub enum WidgetConfig {
|
||||||
|
Battery(BatteryConfig),
|
||||||
|
Date(DateConfig),
|
||||||
|
Komorebi(KomorebiConfig),
|
||||||
|
Media(MediaConfig),
|
||||||
|
Memory(MemoryConfig),
|
||||||
|
Network(NetworkConfig),
|
||||||
|
Storage(StorageConfig),
|
||||||
|
Time(TimeConfig),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetConfig {
|
||||||
|
pub fn as_boxed_bar_widget(&self) -> Box<dyn BarWidget> {
|
||||||
|
match self {
|
||||||
|
WidgetConfig::Battery(config) => Box::new(Battery::from(*config)),
|
||||||
|
WidgetConfig::Date(config) => Box::new(Date::from(config.clone())),
|
||||||
|
WidgetConfig::Komorebi(config) => Box::new(Komorebi::from(*config)),
|
||||||
|
WidgetConfig::Media(config) => Box::new(Media::from(*config)),
|
||||||
|
WidgetConfig::Memory(config) => Box::new(Memory::from(*config)),
|
||||||
|
WidgetConfig::Network(config) => Box::new(Network::from(*config)),
|
||||||
|
WidgetConfig::Storage(config) => Box::new(Storage::from(*config)),
|
||||||
|
WidgetConfig::Time(config) => Box::new(Time::from(config.clone())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ os_info = "3.8"
|
|||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
paste = "1"
|
paste = "1"
|
||||||
regex = "1"
|
regex = "1"
|
||||||
schemars = "0.8"
|
schemars = { workspace = true }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
serde_yaml = { workspace = true }
|
serde_yaml = { workspace = true }
|
||||||
|
|||||||
788
schema.bar.json
Normal file
788
schema.bar.json
Normal file
@@ -0,0 +1,788 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "KomobarConfig",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"left_widgets",
|
||||||
|
"monitor",
|
||||||
|
"right_widgets",
|
||||||
|
"theme"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"font_family": {
|
||||||
|
"description": "Font family",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"description": "Frame options (see: https://docs.rs/egui/latest/egui/containers/struct.Frame.html)",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"outer_margin"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"outer_margin": {
|
||||||
|
"description": "Margin outside the painted frame",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"x",
|
||||||
|
"y"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"x": {
|
||||||
|
"description": "X coordinate",
|
||||||
|
"type": "number",
|
||||||
|
"format": "float"
|
||||||
|
},
|
||||||
|
"y": {
|
||||||
|
"description": "Y coordinate",
|
||||||
|
"type": "number",
|
||||||
|
"format": "float"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"left_widgets": {
|
||||||
|
"description": "Left side widgets (ordered left-to-right)",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Battery"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Battery": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Battery widget",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Date"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Date": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable",
|
||||||
|
"format"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Date widget",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"format": {
|
||||||
|
"description": "Set the Date format",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "Month/Date/Year format (09/08/24)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"MonthDateYear"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Year-Month-Date format (2024-09-08)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"YearMonthDate"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Date-Month-Year format (8-Sep-2024)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"DateMonthYear"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Day Date Month Year format (8 September 2024)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"DayDateMonthYear"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html)",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Custom"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Custom": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Komorebi"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Komorebi": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"focused_window",
|
||||||
|
"layout",
|
||||||
|
"workspaces"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"focused_window": {
|
||||||
|
"description": "Configure the Focused Window widget",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable",
|
||||||
|
"show_icon"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Komorebi Focused Window widget",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"show_icon": {
|
||||||
|
"description": "Show the icon of the currently focused window",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"layout": {
|
||||||
|
"description": "Configure the Layout widget",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Komorebi Layout widget",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"workspaces": {
|
||||||
|
"description": "Configure the Workspaces widget",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable",
|
||||||
|
"hide_empty_workspaces"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Komorebi Workspaces widget",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"hide_empty_workspaces": {
|
||||||
|
"description": "Hide workspaces without any windows",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Media"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Media": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Media widget",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Memory"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Memory": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Memory widget",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Network"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Network": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable",
|
||||||
|
"show_data"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Network widget",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"show_data": {
|
||||||
|
"description": "Show network transfer data",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Storage"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Storage": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Storage widget",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Time"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Time": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable",
|
||||||
|
"format"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Time widget",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"format": {
|
||||||
|
"description": "Set the Time format",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "Twelve-hour format (with seconds)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"TwelveHour"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Twenty-four-hour format (with seconds)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"TwentyFourHour"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html)",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Custom"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Custom": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"monitor": {
|
||||||
|
"description": "Monitor options",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"index"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"index": {
|
||||||
|
"description": "Komorebi monitor index of the monitor on which to render the bar",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"work_area_offset": {
|
||||||
|
"description": "Automatically apply a work area offset for this monitor to accommodate the bar",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"bottom",
|
||||||
|
"left",
|
||||||
|
"right",
|
||||||
|
"top"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"bottom": {
|
||||||
|
"description": "The bottom point in a Win32 Rect",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"left": {
|
||||||
|
"description": "The left point in a Win32 Rect",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"right": {
|
||||||
|
"description": "The right point in a Win32 Rect",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"top": {
|
||||||
|
"description": "The top point in a Win32 Rect",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"right_widgets": {
|
||||||
|
"description": "Right side widgets (ordered left-to-right)",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Battery"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Battery": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Battery widget",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Date"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Date": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable",
|
||||||
|
"format"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Date widget",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"format": {
|
||||||
|
"description": "Set the Date format",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "Month/Date/Year format (09/08/24)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"MonthDateYear"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Year-Month-Date format (2024-09-08)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"YearMonthDate"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Date-Month-Year format (8-Sep-2024)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"DateMonthYear"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Day Date Month Year format (8 September 2024)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"DayDateMonthYear"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html)",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Custom"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Custom": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Komorebi"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Komorebi": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"focused_window",
|
||||||
|
"layout",
|
||||||
|
"workspaces"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"focused_window": {
|
||||||
|
"description": "Configure the Focused Window widget",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable",
|
||||||
|
"show_icon"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Komorebi Focused Window widget",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"show_icon": {
|
||||||
|
"description": "Show the icon of the currently focused window",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"layout": {
|
||||||
|
"description": "Configure the Layout widget",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Komorebi Layout widget",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"workspaces": {
|
||||||
|
"description": "Configure the Workspaces widget",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable",
|
||||||
|
"hide_empty_workspaces"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Komorebi Workspaces widget",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"hide_empty_workspaces": {
|
||||||
|
"description": "Hide workspaces without any windows",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Media"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Media": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Media widget",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Memory"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Memory": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Memory widget",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Network"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Network": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable",
|
||||||
|
"show_data"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Network widget",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"show_data": {
|
||||||
|
"description": "Show network transfer data",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Storage"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Storage": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Storage widget",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Time"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Time": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enable",
|
||||||
|
"format"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"description": "Enable the Time widget",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"format": {
|
||||||
|
"description": "Set the Time format",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "Twelve-hour format (with seconds)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"TwelveHour"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Twenty-four-hour format (with seconds)",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"TwentyFourHour"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Custom format (https://docs.rs/chrono/latest/chrono/format/strftime/index.html)",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"Custom"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Custom": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"theme": {
|
||||||
|
"description": "Theme",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "Default egui theme",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Default"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Catpuccin Frappe",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"CatppuccinFrappe"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Catpuccin Macchiato",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"CatppuccinMacchiato"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Catpuccin Mocha",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"CatppuccinMocha"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"viewport": {
|
||||||
|
"description": "Viewport options (see: https://docs.rs/egui/latest/egui/viewport/struct.ViewportBuilder.html)",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"inner_size": {
|
||||||
|
"description": "The desired size of the bar from the starting position (usually monitor width x desired height)",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"x",
|
||||||
|
"y"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"x": {
|
||||||
|
"description": "X coordinate",
|
||||||
|
"type": "number",
|
||||||
|
"format": "float"
|
||||||
|
},
|
||||||
|
"y": {
|
||||||
|
"description": "Y coordinate",
|
||||||
|
"type": "number",
|
||||||
|
"format": "float"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"description": "The desired starting position of the bar (0,0 = top left of the screen)",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"x",
|
||||||
|
"y"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"x": {
|
||||||
|
"description": "X coordinate",
|
||||||
|
"type": "number",
|
||||||
|
"format": "float"
|
||||||
|
},
|
||||||
|
"y": {
|
||||||
|
"description": "Y coordinate",
|
||||||
|
"type": "number",
|
||||||
|
"format": "float"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user