feat(bar): add widget grouping options

This commit adds various widget grouping and transparency options to
komorebi-bar, and is comprised of the individual commits listed below,
worked on in PR #1108, squashed into one.

e8f5952abb
* adding RenderConfig, and some test frames on widgets

0a5e0a4c0a
* no clone

a5a7d6906c
* comment

6a91dd46cd
* ignore unused

80f0214e47
* Group enum, Copy RenderConfig

fbe5e2c1f7
* Group -> Grouping

ce49b433f9
* GroupingConfig

f446a6a45f
* "fmt --check" fix (thanks VS)

d188222be7
* added widget grouping and group module

1008ec2031
* rounding from settings, and apply_on_side

7fff6d29a9
* dereferencing

655e8ce4c1
* AlphaColour, transparency, bar background, more grouping config options

cba0fcd882
* added RoundingConfig

ec5f7dc82d
* handling grouping edge case for komorebi focus window

12117b832b
* changed default values

645c46beb8
* background color using theme color, AlphaColour.to_color32_or, updating json format for Grouping and RoundingConfig

10d2ab21c7
* hot-reload on grouping

d88774328a
* grouping correction on init

2cd237fd0d
* added shadow to grouping, optional width on grouping stroke

4f4b617f26
* grouping on bar, converting AlphaColour from_rgba_unmultiplied, simplified grouping

3808fcec8f
* widget rounding based on grouping, atomic background color, simplified config, style on grouping

be45d14f6d
* renamed Side to Alignment, group spacing

be45d14f6d
* proper widget spacing based on alignment

b43a5bda69
* added widget_spacing to config

c18e5f4dbe
* test commit

cba2b2f7ac
* refactoring of render and grouping, widget spacing WIP

9311cb00ec
* simplify no_spacing

36c267246b
* correct spacing on komorebi and network widgets (WIP)

85a41bf5b2
* correct widget spacing on all widgets

50b49ccf69
* refactoring widget spacing

9ec67ad988
* account for ui item_spacing when setting the widget_spacing

e88a2fd9c0
* format
This commit is contained in:
CtByte
2024-11-19 04:55:21 +01:00
committed by LGUG2Z
parent e4e94fd1a6
commit 219fa8e14f
15 changed files with 719 additions and 363 deletions
+263
View File
@@ -0,0 +1,263 @@
use crate::bar::Alignment;
use crate::config::KomobarConfig;
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::Ui;
use eframe::egui::Vec2;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind")]
pub enum Grouping {
/// No grouping is applied
None,
/// Widgets are grouped as a whole
Bar(GroupingConfig),
/// Widgets are grouped by alignment
Alignment(GroupingConfig),
/// Widgets are grouped individually
Widget(GroupingConfig),
}
#[derive(Copy, Clone)]
pub struct RenderConfig {
/// Spacing between widgets
pub spacing: f32,
/// Sets how widgets are grouped
pub grouping: Grouping,
/// Background color
pub background_color: Color32,
/// Alignment of the widgets
pub alignment: Option<Alignment>,
/// Add more inner margin when adding a widget group
pub more_inner_margin: bool,
/// Set to true after the first time the apply_on_widget was called on an alignment
pub applied_on_widget: bool,
}
pub trait RenderExt {
fn new_renderconfig(&self, background_color: Color32) -> RenderConfig;
}
impl RenderExt for &KomobarConfig {
fn new_renderconfig(&self, background_color: Color32) -> RenderConfig {
RenderConfig {
spacing: self.widget_spacing.unwrap_or(10.0),
grouping: self.grouping.unwrap_or(Grouping::None),
background_color,
alignment: None,
more_inner_margin: false,
applied_on_widget: false,
}
}
}
impl RenderConfig {
pub fn new() -> Self {
Self {
spacing: 0.0,
grouping: Grouping::None,
background_color: Color32::BLACK,
alignment: None,
more_inner_margin: false,
applied_on_widget: false,
}
}
pub fn apply_on_bar<R>(
&mut self,
ui: &mut Ui,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> {
self.alignment = None;
if let Grouping::Bar(config) = self.grouping {
return self.define_group(None, config, ui, add_contents);
}
Self::fallback_group(ui, add_contents)
}
pub fn apply_on_alignment<R>(
&mut self,
ui: &mut Ui,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> {
self.alignment = None;
if let Grouping::Alignment(config) = self.grouping {
return self.define_group(None, config, ui, add_contents);
}
Self::fallback_group(ui, add_contents)
}
pub fn apply_on_widget<R>(
&mut self,
more_inner_margin: bool,
ui: &mut Ui,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> {
self.more_inner_margin = more_inner_margin;
let outer_margin = self.widget_outer_margin(ui);
if let Grouping::Widget(config) = self.grouping {
return self.define_group(Some(outer_margin), config, ui, add_contents);
}
self.fallback_widget_group(Some(outer_margin), ui, add_contents)
}
fn fallback_group<R>(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
InnerResponse {
inner: add_contents(ui),
response: ui.response().clone(),
}
}
fn fallback_widget_group<R>(
&mut self,
outer_margin: Option<Margin>,
ui: &mut Ui,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> {
Frame::none()
.outer_margin(outer_margin.unwrap_or(Margin::ZERO))
.inner_margin(match self.more_inner_margin {
true => Margin::symmetric(5.0, 0.0),
false => Margin::same(0.0),
})
.show(ui, add_contents)
}
fn define_group<R>(
&mut self,
outer_margin: Option<Margin>,
config: GroupingConfig,
ui: &mut Ui,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> {
Frame::group(ui.style_mut())
.outer_margin(outer_margin.unwrap_or(Margin::ZERO))
.inner_margin(match self.more_inner_margin {
true => Margin::symmetric(8.0, 3.0),
false => Margin::symmetric(3.0, 3.0),
})
.stroke(ui.style().visuals.widgets.noninteractive.bg_stroke)
.rounding(match config.rounding {
Some(rounding) => rounding.into(),
None => ui.style().visuals.widgets.noninteractive.rounding,
})
.fill(
self.background_color
.try_apply_alpha(config.transparency_alpha),
)
.shadow(match config.style {
Some(style) => match style {
// new styles can be added if needed here
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,
})
.show(ui, add_contents)
}
fn widget_outer_margin(&mut self, ui: &mut Ui) -> Margin {
let spacing = if self.applied_on_widget {
// Remove the default item spacing from the margin
self.spacing - ui.spacing().item_spacing.x
} else {
0.0
};
if !self.applied_on_widget {
self.applied_on_widget = true;
}
Margin {
left: match self.alignment {
Some(align) => match align {
Alignment::Left => spacing,
Alignment::Right => 0.0,
},
None => 0.0,
},
right: match self.alignment {
Some(align) => match align {
Alignment::Left => 0.0,
Alignment::Right => spacing,
},
None => 0.0,
},
top: 0.0,
bottom: 0.0,
}
}
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
pub struct GroupingConfig {
/// Styles for the grouping
pub style: Option<GroupingStyle>,
/// Alpha value for the color transparency [[0-255]] (default: 200)
pub transparency_alpha: Option<u8>,
/// Rounding values for the 4 corners. Can be a single or 4 values.
pub rounding: Option<RoundingConfig>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
pub enum GroupingStyle {
Default,
/// A black shadow is added under the default group
DefaultWithShadow,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(untagged)]
pub enum RoundingConfig {
/// All 4 corners are the same
Same(f32),
/// All 4 corners are custom. Order: NW, NE, SW, SE
Individual([f32; 4]),
}
impl From<RoundingConfig> for Rounding {
fn from(value: RoundingConfig) -> Self {
match value {
RoundingConfig::Same(value) => Rounding::same(value),
RoundingConfig::Individual(values) => Self {
nw: values[0],
ne: values[1],
sw: values[2],
se: values[3],
},
}
}
}
pub trait Color32Ext {
fn try_apply_alpha(self, transparency_alpha: Option<u8>) -> Self;
}
impl Color32Ext for Color32 {
/// Tries to apply the alpha value to the Color32
fn try_apply_alpha(self, transparency_alpha: Option<u8>) -> Self {
if let Some(alpha) = transparency_alpha {
return Color32::from_rgba_unmultiplied(self.r(), self.g(), self.b(), alpha);
}
self
}
}