From b69db863f1b3ee50048947fb7c207945dafb3154 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sun, 15 Sep 2024 10:25:47 -0700 Subject: [PATCH] feat(themes): update bar on komorebi.json reload This commit ensures that whenever komorebi.json is updated, komorebi-bar will try to apply whichever theme is set in that file by the user (if one is set). Similarly, if a theme is not set in komorebi.bar.json, komorebi-bar will load the theme set in komorebi.json (if one is set). A new configuration "bar_accent" has been added to the KomorebiTheme struct to make this process as uniform as possible. --- komorebi-bar/src/bar.rs | 199 ++++++++++++++++++++-------------- komorebi-bar/src/config.rs | 20 ++++ komorebi-bar/src/komorebi.rs | 17 +++ komorebi-client/src/lib.rs | 1 + komorebi-themes/src/lib.rs | 4 +- komorebi/src/colour.rs | 11 ++ komorebi/src/static_config.rs | 72 ++++-------- 7 files changed, 189 insertions(+), 135 deletions(-) diff --git a/komorebi-bar/src/bar.rs b/komorebi-bar/src/bar.rs index 7980331b..f53baa8e 100644 --- a/komorebi-bar/src/bar.rs +++ b/komorebi-bar/src/bar.rs @@ -21,6 +21,7 @@ use font_loader::system_fonts::FontPropertyBuilder; use komorebi_themes::catppuccin_egui; use komorebi_themes::Catppuccin; use std::cell::RefCell; +use std::path::PathBuf; use std::rc::Rc; use std::sync::Arc; @@ -31,7 +32,89 @@ pub struct Komobar { pub right_widgets: Vec>, pub rx_gui: Receiver, pub rx_config: Receiver, - pub bg_color: Color32, + pub bg_color: Rc>, +} + +pub fn apply_theme(ctx: &Context, theme: KomobarTheme, bg_color: Rc>) { + match theme { + KomobarTheme::Catppuccin { + name: catppuccin, + accent: catppuccin_value, + } => match catppuccin { + Catppuccin::Frappe => { + catppuccin_egui::set_theme(ctx, catppuccin_egui::FRAPPE); + let catppuccin_value = catppuccin_value.unwrap_or_default(); + let accent = catppuccin_value.color32(catppuccin.as_theme()); + + ctx.style_mut(|style| { + style.visuals.selection.stroke.color = accent; + style.visuals.widgets.hovered.fg_stroke.color = accent; + style.visuals.widgets.active.fg_stroke.color = accent; + style.visuals.override_text_color = None; + }); + + bg_color.replace(catppuccin_egui::FRAPPE.base); + } + Catppuccin::Latte => { + catppuccin_egui::set_theme(ctx, catppuccin_egui::LATTE); + let catppuccin_value = catppuccin_value.unwrap_or_default(); + let accent = catppuccin_value.color32(catppuccin.as_theme()); + + ctx.style_mut(|style| { + style.visuals.selection.stroke.color = accent; + style.visuals.widgets.hovered.fg_stroke.color = accent; + style.visuals.widgets.active.fg_stroke.color = accent; + style.visuals.override_text_color = None; + }); + + bg_color.replace(catppuccin_egui::LATTE.base); + } + Catppuccin::Macchiato => { + catppuccin_egui::set_theme(ctx, catppuccin_egui::MACCHIATO); + let catppuccin_value = catppuccin_value.unwrap_or_default(); + let accent = catppuccin_value.color32(catppuccin.as_theme()); + + ctx.style_mut(|style| { + style.visuals.selection.stroke.color = accent; + style.visuals.widgets.hovered.fg_stroke.color = accent; + style.visuals.widgets.active.fg_stroke.color = accent; + style.visuals.override_text_color = None; + }); + + bg_color.replace(catppuccin_egui::MACCHIATO.base); + } + Catppuccin::Mocha => { + catppuccin_egui::set_theme(ctx, catppuccin_egui::MOCHA); + let catppuccin_value = catppuccin_value.unwrap_or_default(); + let accent = catppuccin_value.color32(catppuccin.as_theme()); + + ctx.style_mut(|style| { + style.visuals.selection.stroke.color = accent; + style.visuals.widgets.hovered.fg_stroke.color = accent; + style.visuals.widgets.active.fg_stroke.color = accent; + style.visuals.override_text_color = None; + }); + + bg_color.replace(catppuccin_egui::MOCHA.base); + } + }, + KomobarTheme::Base16 { + name: base16, + accent: base16_value, + } => { + ctx.set_style(base16.style()); + let base16_value = base16_value.unwrap_or_default(); + let accent = base16_value.color32(base16); + + ctx.style_mut(|style| { + style.visuals.selection.stroke.color = accent; + style.visuals.widgets.hovered.fg_stroke.color = accent; + style.visuals.widgets.active.fg_stroke.color = accent; + }); + + bg_color.replace(base16.background()); + } + } } impl Komobar { @@ -47,89 +130,36 @@ impl Komobar { } match config.theme { - None => { - ctx.set_style(Style::default()); - self.bg_color = Style::default().visuals.panel_fill; + Some(theme) => { + apply_theme(ctx, theme, self.bg_color.clone()); } - Some(theme) => match theme { - KomobarTheme::Catppuccin { - name: catppuccin, - accent: catppuccin_value, - } => match catppuccin { - Catppuccin::Frappe => { - catppuccin_egui::set_theme(ctx, catppuccin_egui::FRAPPE); - let catppuccin_value = catppuccin_value.unwrap_or_default(); - let accent = catppuccin_value.color32(catppuccin.as_theme()); + None => { + 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); - ctx.style_mut(|style| { - style.visuals.selection.stroke.color = accent; - style.visuals.widgets.hovered.fg_stroke.color = accent; - style.visuals.widgets.active.fg_stroke.color = accent; - style.visuals.override_text_color = None; - }); + if home.as_path().is_dir() { + home + } else { + panic!("$Env:KOMOREBI_CONFIG_HOME is set to '{home_path}', which is not a valid directory"); + } + }, + ); - self.bg_color = catppuccin_egui::FRAPPE.base; + let config = home_dir.join("komorebi.json"); + match komorebi_client::StaticConfig::read(&config) { + Ok(config) => { + if let Some(theme) = config.theme { + apply_theme(ctx, KomobarTheme::from(theme), self.bg_color.clone()); + } } - Catppuccin::Latte => { - catppuccin_egui::set_theme(ctx, catppuccin_egui::LATTE); - let catppuccin_value = catppuccin_value.unwrap_or_default(); - let accent = catppuccin_value.color32(catppuccin.as_theme()); - - ctx.style_mut(|style| { - style.visuals.selection.stroke.color = accent; - style.visuals.widgets.hovered.fg_stroke.color = accent; - style.visuals.widgets.active.fg_stroke.color = accent; - style.visuals.override_text_color = None; - }); - - self.bg_color = catppuccin_egui::LATTE.base; + Err(_) => { + ctx.set_style(Style::default()); + self.bg_color.replace(Style::default().visuals.panel_fill); } - Catppuccin::Macchiato => { - catppuccin_egui::set_theme(ctx, catppuccin_egui::MACCHIATO); - let catppuccin_value = catppuccin_value.unwrap_or_default(); - let accent = catppuccin_value.color32(catppuccin.as_theme()); - - ctx.style_mut(|style| { - style.visuals.selection.stroke.color = accent; - style.visuals.widgets.hovered.fg_stroke.color = accent; - style.visuals.widgets.active.fg_stroke.color = accent; - style.visuals.override_text_color = None; - }); - - self.bg_color = catppuccin_egui::MACCHIATO.base; - } - Catppuccin::Mocha => { - catppuccin_egui::set_theme(ctx, catppuccin_egui::MOCHA); - let catppuccin_value = catppuccin_value.unwrap_or_default(); - let accent = catppuccin_value.color32(catppuccin.as_theme()); - - ctx.style_mut(|style| { - style.visuals.selection.stroke.color = accent; - style.visuals.widgets.hovered.fg_stroke.color = accent; - style.visuals.widgets.active.fg_stroke.color = accent; - style.visuals.override_text_color = None; - }); - - self.bg_color = catppuccin_egui::MOCHA.base; - } - }, - KomobarTheme::Base16 { - name: base16, - accent: base16_value, - } => { - ctx.set_style(base16.style()); - let base16_value = base16_value.unwrap_or_default(); - let accent = base16_value.color32(base16); - - ctx.style_mut(|style| { - style.visuals.selection.stroke.color = accent; - style.visuals.widgets.hovered.fg_stroke.color = accent; - style.visuals.widgets.active.fg_stroke.color = accent; - }); - - self.bg_color = base16.background(); } - }, + } } let mut komorebi_widget = None; @@ -210,7 +240,7 @@ impl Komobar { right_widgets: vec![], rx_gui, rx_config, - bg_color: Style::default().visuals.panel_fill, + bg_color: Rc::new(RefCell::new(Style::default().visuals.panel_fill)), }; komobar.apply_config(&cc.egui_ctx, &config, None); @@ -267,7 +297,12 @@ impl eframe::App for Komobar { 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()); + .handle_notification( + ctx, + self.config.monitor.index, + self.rx_gui.clone(), + self.bg_color.clone(), + ); } let frame = if let Some(frame) = &self.config.frame { @@ -276,9 +311,9 @@ impl eframe::App for Komobar { frame.inner_margin.x, frame.inner_margin.y, )) - .fill(self.bg_color) + .fill(*self.bg_color.borrow()) } else { - Frame::none().fill(self.bg_color) + Frame::none().fill(*self.bg_color.borrow()) }; CentralPanel::default().frame(frame).show(ctx, |ui| { diff --git a/komorebi-bar/src/config.rs b/komorebi-bar/src/config.rs index eeeb32da..071594db 100644 --- a/komorebi-bar/src/config.rs +++ b/komorebi-bar/src/config.rs @@ -2,6 +2,7 @@ use crate::widget::WidgetConfig; use eframe::egui::Pos2; use eframe::egui::TextBuffer; use eframe::egui::Vec2; +use komorebi_client::KomorebiTheme; use komorebi_client::Rect; use schemars::JsonSchema; use serde::Deserialize; @@ -107,3 +108,22 @@ pub enum KomobarTheme { accent: Option, }, } + +impl From for KomobarTheme { + fn from(value: KomorebiTheme) -> Self { + match value { + KomorebiTheme::Catppuccin { + name, bar_accent, .. + } => Self::Catppuccin { + name, + accent: bar_accent, + }, + KomorebiTheme::Base16 { + name, bar_accent, .. + } => Self::Base16 { + name, + accent: bar_accent, + }, + } + } +} diff --git a/komorebi-bar/src/komorebi.rs b/komorebi-bar/src/komorebi.rs index 8effde13..e9471605 100644 --- a/komorebi-bar/src/komorebi.rs +++ b/komorebi-bar/src/komorebi.rs @@ -1,6 +1,9 @@ +use crate::bar::apply_theme; +use crate::config::KomobarTheme; use crate::widget::BarWidget; use crate::WIDGET_SPACING; use crossbeam_channel::Receiver; +use eframe::egui::Color32; use eframe::egui::ColorImage; use eframe::egui::Context; use eframe::egui::Image; @@ -12,6 +15,7 @@ use eframe::egui::TextureOptions; use eframe::egui::Ui; use image::RgbaImage; use komorebi_client::CycleDirection; +use komorebi_client::NotificationEvent; use komorebi_client::SocketMessage; use schemars::JsonSchema; use serde::Deserialize; @@ -169,10 +173,23 @@ impl KomorebiNotificationState { pub fn handle_notification( &mut self, + ctx: &Context, monitor_index: usize, rx_gui: Receiver, + bg_color: Rc>, ) { if let Ok(notification) = rx_gui.try_recv() { + if let NotificationEvent::Socket(SocketMessage::ReloadStaticConfiguration(path)) = + notification.event + { + if let Ok(config) = komorebi_client::StaticConfig::read(&path) { + if let Some(theme) = config.theme { + apply_theme(ctx, KomobarTheme::from(theme), bg_color); + tracing::info!("applied theme from updated komorebi.json"); + } + } + } + let monitor = ¬ification.state.monitors.elements()[monitor_index]; let focused_workspace_idx = monitor.focused_workspace_idx(); diff --git a/komorebi-client/src/lib.rs b/komorebi-client/src/lib.rs index 9a9662e9..f84d2ce5 100644 --- a/komorebi-client/src/lib.rs +++ b/komorebi-client/src/lib.rs @@ -36,6 +36,7 @@ pub use komorebi::window_manager_event::WindowManagerEvent; pub use komorebi::workspace::Workspace; pub use komorebi::BorderColours; pub use komorebi::GlobalState; +pub use komorebi::KomorebiTheme; pub use komorebi::Notification; pub use komorebi::NotificationEvent; pub use komorebi::RuleDebug; diff --git a/komorebi-themes/src/lib.rs b/komorebi-themes/src/lib.rs index c042b5ab..c6ec7b64 100644 --- a/komorebi-themes/src/lib.rs +++ b/komorebi-themes/src/lib.rs @@ -1,13 +1,13 @@ #![warn(clippy::all)] #![allow(clippy::missing_errors_doc)] -pub use base16_egui_themes::Base16; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; +pub use base16_egui_themes::Base16; pub use catppuccin_egui; -use egui::Color32; +pub use egui::Color32; #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] #[serde(tag = "type")] diff --git a/komorebi/src/colour.rs b/komorebi/src/colour.rs index 3166a382..7e69a920 100644 --- a/komorebi/src/colour.rs +++ b/komorebi/src/colour.rs @@ -1,4 +1,5 @@ use hex_color::HexColor; +use komorebi_themes::Color32; use schemars::gen::SchemaGenerator; use schemars::schema::InstanceType; use schemars::schema::Schema; @@ -28,6 +29,16 @@ impl From for Colour { } } +impl From for Colour { + fn from(value: Color32) -> Self { + Colour::Rgb(Rgb::new( + value.r() as u32, + value.g() as u32, + value.b() as u32, + )) + } +} + #[derive(Debug, Copy, Clone, Serialize, Deserialize)] pub struct Hex(HexColor); diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index 8c0138bc..bf3e2b78 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -27,7 +27,6 @@ use crate::window_manager_event::WindowManagerEvent; use crate::windows_api::WindowsApi; use crate::workspace::Workspace; use crate::CrossBoundaryBehaviour; -use crate::Rgb; use crate::ANIMATION_DURATION; use crate::ANIMATION_ENABLED; use crate::ANIMATION_FPS; @@ -396,6 +395,8 @@ pub enum KomorebiTheme { stackbar_unfocused_text: Option, /// Stackbar tab background colour (default: Base) stackbar_background: Option, + /// Komorebi status bar accent (default: Blue) + bar_accent: Option, }, /// A theme from base16-egui-themes Base16 { @@ -415,6 +416,8 @@ pub enum KomorebiTheme { stackbar_unfocused_text: Option, /// Stackbar tab background colour (default: Base01) stackbar_background: Option, + /// Komorebi status bar accent (default: Base0D) + bar_accent: Option, }, } @@ -848,6 +851,7 @@ impl StaticConfig { stackbar_focused_text, stackbar_unfocused_text, stackbar_background, + .. } => { let single_border = single_border .unwrap_or(komorebi_themes::CatppuccinValue::Blue) @@ -896,6 +900,7 @@ impl StaticConfig { stackbar_focused_text, stackbar_unfocused_text, stackbar_background, + .. } => { let single_border = single_border .unwrap_or(komorebi_themes::Base16Value::Base0D) @@ -937,66 +942,25 @@ impl StaticConfig { } }; - border_manager::FOCUSED.store( - u32::from(Colour::Rgb(Rgb::new( - single_border.r() as u32, - single_border.g() as u32, - single_border.b() as u32, - ))), - Ordering::SeqCst, - ); - - border_manager::MONOCLE.store( - u32::from(Colour::Rgb(Rgb::new( - monocle_border.r() as u32, - monocle_border.g() as u32, - monocle_border.b() as u32, - ))), - Ordering::SeqCst, - ); - - border_manager::STACK.store( - u32::from(Colour::Rgb(Rgb::new( - stack_border.r() as u32, - stack_border.g() as u32, - stack_border.b() as u32, - ))), - Ordering::SeqCst, - ); - - border_manager::UNFOCUSED.store( - u32::from(Colour::Rgb(Rgb::new( - unfocused_border.r() as u32, - unfocused_border.g() as u32, - unfocused_border.b() as u32, - ))), - Ordering::SeqCst, - ); + border_manager::FOCUSED.store(u32::from(Colour::from(single_border)), Ordering::SeqCst); + border_manager::MONOCLE + .store(u32::from(Colour::from(monocle_border)), Ordering::SeqCst); + border_manager::STACK.store(u32::from(Colour::from(stack_border)), Ordering::SeqCst); + border_manager::UNFOCUSED + .store(u32::from(Colour::from(unfocused_border)), Ordering::SeqCst); STACKBAR_TAB_BACKGROUND_COLOUR.store( - u32::from(Colour::Rgb(Rgb::new( - stackbar_background.r() as u32, - stackbar_background.g() as u32, - stackbar_background.b() as u32, - ))), + u32::from(Colour::from(stackbar_background)), Ordering::SeqCst, ); STACKBAR_FOCUSED_TEXT_COLOUR.store( - u32::from(Colour::Rgb(Rgb::new( - stackbar_focused_text.r() as u32, - stackbar_focused_text.g() as u32, - stackbar_focused_text.b() as u32, - ))), + u32::from(Colour::from(stackbar_focused_text)), Ordering::SeqCst, ); STACKBAR_UNFOCUSED_TEXT_COLOUR.store( - u32::from(Colour::Rgb(Rgb::new( - stackbar_unfocused_text.r() as u32, - stackbar_unfocused_text.g() as u32, - stackbar_unfocused_text.b() as u32, - ))), + u32::from(Colour::from(stackbar_unfocused_text)), Ordering::SeqCst, ); } @@ -1053,6 +1017,12 @@ impl StaticConfig { Ok(()) } + pub fn read(path: &PathBuf) -> Result { + let content = std::fs::read_to_string(path)?; + let value: Self = serde_json::from_str(&content)?; + Ok(value) + } + #[allow(clippy::too_many_lines)] pub fn preload( path: &PathBuf,