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.
This commit is contained in:
LGUG2Z
2024-09-15 10:25:47 -07:00
parent 286bb0070c
commit b69db863f1
7 changed files with 189 additions and 135 deletions

View File

@@ -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<Box<dyn BarWidget>>,
pub rx_gui: Receiver<komorebi_client::Notification>,
pub rx_config: Receiver<KomobarConfig>,
pub bg_color: Color32,
pub bg_color: Rc<RefCell<Color32>>,
}
pub fn apply_theme(ctx: &Context, theme: KomobarTheme, bg_color: Rc<RefCell<Color32>>) {
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| {

View File

@@ -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<komorebi_themes::Base16Value>,
},
}
impl From<KomorebiTheme> 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,
},
}
}
}

View File

@@ -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<komorebi_client::Notification>,
bg_color: Rc<RefCell<Color32>>,
) {
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 = &notification.state.monitors.elements()[monitor_index];
let focused_workspace_idx = monitor.focused_workspace_idx();

View File

@@ -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;

View File

@@ -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")]

View File

@@ -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<u32> for Colour {
}
}
impl From<Color32> 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);

View File

@@ -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<komorebi_themes::CatppuccinValue>,
/// Stackbar tab background colour (default: Base)
stackbar_background: Option<komorebi_themes::CatppuccinValue>,
/// Komorebi status bar accent (default: Blue)
bar_accent: Option<komorebi_themes::CatppuccinValue>,
},
/// A theme from base16-egui-themes
Base16 {
@@ -415,6 +416,8 @@ pub enum KomorebiTheme {
stackbar_unfocused_text: Option<komorebi_themes::Base16Value>,
/// Stackbar tab background colour (default: Base01)
stackbar_background: Option<komorebi_themes::Base16Value>,
/// Komorebi status bar accent (default: Base0D)
bar_accent: Option<komorebi_themes::Base16Value>,
},
}
@@ -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<Self> {
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,