From 3808fcec8fd3ab2709def38338413773a0573659 Mon Sep 17 00:00:00 2001 From: Csaba Date: Tue, 12 Nov 2024 00:16:02 +0100 Subject: [PATCH] widget rounding based on grouping, atomic background color, simplified config, style on grouping --- komorebi-bar/src/bar.rs | 31 ++++++-- komorebi-bar/src/config.rs | 50 +++++++------ komorebi-bar/src/group.rs | 147 +++++++++++-------------------------- komorebi-bar/src/main.rs | 7 +- 4 files changed, 97 insertions(+), 138 deletions(-) diff --git a/komorebi-bar/src/bar.rs b/komorebi-bar/src/bar.rs index eda9e53a..c239b427 100644 --- a/komorebi-bar/src/bar.rs +++ b/komorebi-bar/src/bar.rs @@ -1,3 +1,4 @@ +use crate::config::Color32Ext; use crate::config::KomobarConfig; use crate::config::KomobarTheme; use crate::config::Position; @@ -9,6 +10,7 @@ use crate::process_hwnd; use crate::widget::BarWidget; use crate::widget::RenderConfig; use crate::widget::WidgetConfig; +use crate::BACKGROUND_COLOR; use crate::BAR_HEIGHT; use crate::MAX_LABEL_WIDTH; use crate::MONITOR_LEFT; @@ -194,8 +196,6 @@ impl Komobar { } } - self.render_config.replace(config.into()); - match config.theme { Some(theme) => { apply_theme(ctx, theme, self.bg_color.clone()); @@ -244,13 +244,30 @@ impl Komobar { } } - if let Some(background) = self.config.background { - let theme_color = *self.bg_color.borrow(); - - self.bg_color - .replace(background.to_color32_or(Some(theme_color))); + // apply rounding to the widgets + if let Some(Grouping::Bar(config) | Grouping::Side(config) | Grouping::Widget(config)) = + &config.grouping + { + if let Some(rounding) = config.rounding { + ctx.style_mut(|style| { + style.visuals.widgets.noninteractive.rounding = rounding.into(); + style.visuals.widgets.inactive.rounding = rounding.into(); + style.visuals.widgets.hovered.rounding = rounding.into(); + style.visuals.widgets.active.rounding = rounding.into(); + style.visuals.widgets.open.rounding = rounding.into(); + }); + } } + self.render_config.replace(config.into()); + + let theme_color = *self.bg_color.borrow(); + + BACKGROUND_COLOR.store(theme_color.to_u32(), Ordering::SeqCst); + + self.bg_color + .replace(theme_color.try_apply_alpha(self.config.transparency_alpha)); + if let Some(font_size) = &config.font_size { tracing::info!("attempting to set custom font size: {font_size}"); Self::set_font_size(ctx, *font_size); diff --git a/komorebi-bar/src/config.rs b/komorebi-bar/src/config.rs index e6ee5d9e..fc394813 100644 --- a/komorebi-bar/src/config.rs +++ b/komorebi-bar/src/config.rs @@ -5,7 +5,6 @@ use eframe::egui::Color32; use eframe::egui::Pos2; use eframe::egui::TextBuffer; use eframe::egui::Vec2; -use komorebi_client::Colour; use komorebi_client::KomorebiTheme; use komorebi_client::Rect; use schemars::JsonSchema; @@ -32,8 +31,8 @@ pub struct KomobarConfig { pub max_label_width: Option, /// Theme pub theme: Option, - /// Background color - pub background: Option, + /// Alpha value for the color transparency [[0-255]] (default: 200) + pub transparency_alpha: Option, /// Visual grouping for widgets pub grouping: Option, /// Left side widgets (ordered left-to-right) @@ -198,29 +197,36 @@ pub enum LabelPrefix { IconAndText, } -#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub struct AlphaColour { - /// Color - pub color: Option, - /// Alpha value for the color transparency [[0-255]] (default: 200) - pub transparency_alpha: Option, +pub trait Color32Ext { + fn to_u32(&self) -> u32; + fn from_u32(color: u32) -> Self; + fn try_apply_alpha(self, transparency_alpha: Option) -> Self; } -impl AlphaColour { - /// Returns an Rgb or Rgba color using the alpha, and default_color or Rgb(0,0,0) - pub fn to_color32_or(self, default_color: Option) -> Color32 { - let color = match self.color { - Some(color) => color.into(), - None => match default_color { - Some(color) => color, - None => Color32::from_rgb(0, 0, 0), - }, - }; +impl Color32Ext for Color32 { + /// Converts Color32 to u32 (ARGB format) + fn to_u32(&self) -> u32 { + ((self.a() as u32) << 24) + | ((self.r() as u32) << 16) + | ((self.g() as u32) << 8) + | (self.b() as u32) + } - if let Some(alpha) = self.transparency_alpha { - return Color32::from_rgba_unmultiplied(color.r(), color.g(), color.b(), alpha); + /// Converts u32 back to Color32 (ARGB format) + fn from_u32(color: u32) -> Self { + let a = ((color >> 24) & 0xFF) as u8; + let r = ((color >> 16) & 0xFF) as u8; + let g = ((color >> 8) & 0xFF) as u8; + let b = (color & 0xFF) as u8; + Color32::from_rgba_premultiplied(r, g, b, a) + } + + /// Tries to apply the alpha value to the Color32 + fn try_apply_alpha(self, transparency_alpha: Option) -> Self { + if let Some(alpha) = transparency_alpha { + return Color32::from_rgba_unmultiplied(self.r(), self.g(), self.b(), alpha); } - color + self } } diff --git a/komorebi-bar/src/group.rs b/komorebi-bar/src/group.rs index 59e48fc8..21c59ff2 100644 --- a/komorebi-bar/src/group.rs +++ b/komorebi-bar/src/group.rs @@ -1,19 +1,17 @@ -use crate::config::AlphaColour; -use crate::config::Position; +use crate::config::Color32Ext; +use crate::BACKGROUND_COLOR; use eframe::egui::Color32; use eframe::egui::Frame; use eframe::egui::InnerResponse; use eframe::egui::Margin; use eframe::egui::Rounding; use eframe::egui::Shadow; -use eframe::egui::Stroke; use eframe::egui::Ui; use eframe::egui::Vec2; -use komorebi_client::Colour; -use komorebi_client::Rect; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; +use std::sync::atomic::Ordering; #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] #[serde(tag = "kind")] @@ -36,21 +34,8 @@ impl Grouping { ) -> InnerResponse { match self { Self::Bar(config) => Self::define_frame(ui, config).show(ui, add_contents), + Self::Side(_) => Self::default_response(ui, add_contents), Self::Widget(_) => Self::default_response(ui, add_contents), - Self::Side(_) => Self::default_response(ui, add_contents), - Self::None => Self::default_response(ui, add_contents), - } - } - - pub fn apply_on_widget( - &mut self, - ui: &mut Ui, - add_contents: impl FnOnce(&mut Ui) -> R, - ) -> InnerResponse { - match self { - Self::Bar(_) => Self::default_response(ui, add_contents), - Self::Widget(config) => Self::define_frame(ui, config).show(ui, add_contents), - Self::Side(_) => Self::default_response(ui, add_contents), Self::None => Self::default_response(ui, add_contents), } } @@ -62,36 +47,49 @@ impl Grouping { ) -> InnerResponse { match self { Self::Bar(_) => Self::default_response(ui, add_contents), - Self::Widget(_) => Self::default_response(ui, add_contents), Self::Side(config) => Self::define_frame(ui, config).show(ui, add_contents), + Self::Widget(_) => Self::default_response(ui, add_contents), + Self::None => Self::default_response(ui, add_contents), + } + } + + pub fn apply_on_widget( + &mut self, + ui: &mut Ui, + add_contents: impl FnOnce(&mut Ui) -> R, + ) -> InnerResponse { + match self { + Self::Bar(_) => Self::default_response(ui, add_contents), + Self::Side(_) => Self::default_response(ui, add_contents), + Self::Widget(config) => Self::define_frame(ui, config).show(ui, add_contents), Self::None => Self::default_response(ui, add_contents), } } fn define_frame(ui: &mut Ui, config: &mut GroupingConfig) -> Frame { Frame::none() - .fill(match config.fill { - Some(color) => color.to_color32_or(None), - None => Color32::TRANSPARENT, - }) - .outer_margin(match config.outer_margin { - Some(margin) => Self::rect_to_margin(margin), - None => Margin::symmetric(0.0, 0.0), - }) - .inner_margin(match config.inner_margin { - Some(margin) => Self::rect_to_margin(margin), - None => Margin::symmetric(5.0, 2.0), - }) + .outer_margin(Margin::same(0.0)) + .inner_margin(Margin::symmetric(3.0, 3.0)) + .stroke(ui.style().visuals.widgets.noninteractive.bg_stroke) .rounding(match config.rounding { Some(rounding) => rounding.into(), - None => Rounding::same(5.0), + None => ui.style().visuals.widgets.noninteractive.rounding, }) - .stroke(match config.stroke { - Some(line) => line.into(), - None => ui.style().visuals.widgets.noninteractive.bg_stroke, - }) - .shadow(match config.shadow { - Some(shadow) => shadow.into(), + .fill( + Color32::from_u32(BACKGROUND_COLOR.load(Ordering::SeqCst)) + .try_apply_alpha(config.transparency_alpha), + ) + .shadow(match config.style { + Some(style) => match style { + // new styles can be added if needed + GroupingStyle::Default => Shadow::NONE, + GroupingStyle::DefaultWithShadow => Shadow { + blur: 4.0, + offset: Vec2::new(1.0, 1.0), + spread: 3.0, + color: Color32::BLACK.try_apply_alpha(config.transparency_alpha), + }, + }, None => Shadow::NONE, }) } @@ -105,43 +103,19 @@ impl Grouping { response: ui.response().clone(), } } - - fn rect_to_margin(rect: Rect) -> Margin { - Margin { - left: rect.left as f32, - right: rect.right as f32, - top: rect.top as f32, - bottom: rect.bottom as f32, - } - } } #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] pub struct GroupingConfig { - pub fill: Option, + pub style: Option, + pub transparency_alpha: Option, pub rounding: Option, - pub outer_margin: Option, - pub inner_margin: Option, - pub stroke: Option, - pub shadow: Option, } #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub struct Line { - pub width: Option, - pub color: Option, -} - -impl From for Stroke { - fn from(value: Line) -> Self { - Self { - width: value.width.unwrap_or(1.0), - color: match value.color { - Some(color) => color.into(), - None => Color32::from_rgb(0, 0, 0), - }, - } - } +pub enum GroupingStyle { + Default, + DefaultWithShadow, } #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] @@ -166,40 +140,3 @@ impl From for Rounding { } } } - -#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub struct BoxShadow { - /// Move the shadow by this much. - /// - /// For instance, a value of `[1.0, 2.0]` will move the shadow 1 point to the right and 2 points down, - /// causing a drop-shadow effect. - pub offset: Option, - - /// The width of the blur, i.e. the width of the fuzzy penumbra. - /// - /// A value of 0.0 means a sharp shadow. - pub blur: Option, - - /// Expand the shadow in all directions by this much. - pub spread: Option, - - /// Color of the opaque center of the shadow. - pub color: Option, -} - -impl From for Shadow { - fn from(value: BoxShadow) -> Self { - Shadow { - offset: match value.offset { - Some(offset) => offset.into(), - None => Vec2::ZERO, - }, - blur: value.blur.unwrap_or(0.0), - spread: value.spread.unwrap_or(0.0), - color: match value.color { - Some(color) => color.to_color32_or(None), - None => Color32::TRANSPARENT, - }, - } - } -} diff --git a/komorebi-bar/src/main.rs b/komorebi-bar/src/main.rs index b179ac0e..9def465f 100644 --- a/komorebi-bar/src/main.rs +++ b/komorebi-bar/src/main.rs @@ -29,6 +29,7 @@ use std::io::BufReader; use std::io::Read; use std::path::PathBuf; use std::sync::atomic::AtomicI32; +use std::sync::atomic::AtomicU32; use std::sync::atomic::Ordering; use std::sync::Arc; use std::time::Duration; @@ -45,6 +46,7 @@ use windows::Win32::UI::WindowsAndMessaging::GetWindowThreadProcessId; pub static WIDGET_SPACING: f32 = 10.0; +pub static BACKGROUND_COLOR: AtomicU32 = AtomicU32::new(0); pub static MAX_LABEL_WIDTH: AtomicI32 = AtomicI32::new(400); pub static MONITOR_LEFT: AtomicI32 = AtomicI32::new(0); pub static MONITOR_TOP: AtomicI32 = AtomicI32::new(0); @@ -267,10 +269,7 @@ fn main() -> color_eyre::Result<()> { let viewport_builder = ViewportBuilder::default() .with_decorations(false) - .with_transparent(match config.background { - None => false, - Some(color) => color.transparency_alpha.is_some(), - }) + .with_transparent(config.transparency_alpha.is_some()) .with_taskbar(false); let native_options = eframe::NativeOptions {