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-18 19:56:00 -08:00
committed by LGUG2Z
parent e4e94fd1a6
commit 219fa8e14f
15 changed files with 719 additions and 363 deletions
+231 -206
View File
@@ -1,9 +1,9 @@
use crate::bar::apply_theme;
use crate::config::KomobarTheme;
use crate::render::RenderConfig;
use crate::ui::CustomUi;
use crate::widget::BarWidget;
use crate::MAX_LABEL_WIDTH;
use crate::WIDGET_SPACING;
use crossbeam_channel::Receiver;
use crossbeam_channel::TryRecvError;
use eframe::egui::text::LayoutJob;
@@ -122,102 +122,123 @@ pub struct Komorebi {
}
impl BarWidget for Komorebi {
fn render(&mut self, ctx: &Context, ui: &mut Ui) {
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
let mut komorebi_notification_state = self.komorebi_notification_state.borrow_mut();
if self.workspaces.enable {
let mut update = None;
for (i, (ws, should_show)) in komorebi_notification_state.workspaces.iter().enumerate()
{
if *should_show
&& ui
.add(SelectableLabel::new(
komorebi_notification_state.selected_workspace.eq(ws),
ws.to_string(),
))
.clicked()
// NOTE: There should always be at least one workspace if the bar is connected to komorebi.
config.apply_on_widget(false, ui, |ui| {
for (i, (ws, should_show)) in
komorebi_notification_state.workspaces.iter().enumerate()
{
update = Some(ws.to_string());
let mut proceed = true;
if komorebi_client::send_message(&SocketMessage::MouseFollowsFocus(false))
.is_err()
if *should_show
&& ui
.add(SelectableLabel::new(
komorebi_notification_state.selected_workspace.eq(ws),
ws.to_string(),
))
.clicked()
{
tracing::error!("could not send message to komorebi: MouseFollowsFocus");
proceed = false;
}
update = Some(ws.to_string());
let mut proceed = true;
if proceed
&& komorebi_client::send_message(&SocketMessage::FocusWorkspaceNumber(i))
if komorebi_client::send_message(&SocketMessage::MouseFollowsFocus(false))
.is_err()
{
tracing::error!("could not send message to komorebi: FocusWorkspaceNumber");
proceed = false;
}
{
tracing::error!(
"could not send message to komorebi: MouseFollowsFocus"
);
proceed = false;
}
if proceed
&& komorebi_client::send_message(&SocketMessage::MouseFollowsFocus(
komorebi_notification_state.mouse_follows_focus,
))
.is_err()
{
tracing::error!("could not send message to komorebi: MouseFollowsFocus");
proceed = false;
}
if proceed
&& komorebi_client::send_message(&SocketMessage::RetileWithResizeDimensions)
if proceed
&& komorebi_client::send_message(&SocketMessage::FocusWorkspaceNumber(
i,
))
.is_err()
{
tracing::error!("could not send message to komorebi: Retile");
{
tracing::error!(
"could not send message to komorebi: FocusWorkspaceNumber"
);
proceed = false;
}
if proceed
&& komorebi_client::send_message(&SocketMessage::MouseFollowsFocus(
komorebi_notification_state.mouse_follows_focus,
))
.is_err()
{
tracing::error!(
"could not send message to komorebi: MouseFollowsFocus"
);
proceed = false;
}
if proceed
&& komorebi_client::send_message(
&SocketMessage::RetileWithResizeDimensions,
)
.is_err()
{
tracing::error!("could not send message to komorebi: Retile");
}
}
}
}
});
if let Some(update) = update {
komorebi_notification_state.selected_workspace = update;
}
ui.add_space(WIDGET_SPACING);
}
if let Some(layout) = self.layout {
if layout.enable {
if ui
.add(
Label::new(komorebi_notification_state.layout.to_string())
.selectable(false)
.sense(Sense::click()),
)
.clicked()
{
match komorebi_notification_state.layout {
KomorebiLayout::Default(_) => {
if komorebi_client::send_message(&SocketMessage::CycleLayout(
CycleDirection::Next,
))
.is_err()
{
tracing::error!("could not send message to komorebi: CycleLayout");
config.apply_on_widget(true, ui, |ui| {
if ui
.add(
Label::new(komorebi_notification_state.layout.to_string())
.selectable(false)
.sense(Sense::click()),
)
.clicked()
{
match komorebi_notification_state.layout {
KomorebiLayout::Default(_) => {
if komorebi_client::send_message(&SocketMessage::CycleLayout(
CycleDirection::Next,
))
.is_err()
{
tracing::error!(
"could not send message to komorebi: CycleLayout"
);
}
}
}
KomorebiLayout::Floating => {
if komorebi_client::send_message(&SocketMessage::ToggleTiling).is_err()
{
tracing::error!("could not send message to komorebi: ToggleTiling");
KomorebiLayout::Floating => {
if komorebi_client::send_message(&SocketMessage::ToggleTiling)
.is_err()
{
tracing::error!(
"could not send message to komorebi: ToggleTiling"
);
}
}
}
KomorebiLayout::Paused => {
if komorebi_client::send_message(&SocketMessage::TogglePause).is_err() {
tracing::error!("could not send message to komorebi: TogglePause");
KomorebiLayout::Paused => {
if komorebi_client::send_message(&SocketMessage::TogglePause)
.is_err()
{
tracing::error!(
"could not send message to komorebi: TogglePause"
);
}
}
KomorebiLayout::Custom => {}
}
KomorebiLayout::Custom => {}
}
}
ui.add_space(WIDGET_SPACING);
});
}
}
@@ -225,170 +246,174 @@ impl BarWidget for Komorebi {
if configuration_switcher.enable {
for (name, location) in configuration_switcher.configurations.iter() {
let path = PathBuf::from(location);
if path.is_file()
&& ui
if path.is_file() {
config.apply_on_widget(true, ui,|ui|{
if ui
.add(Label::new(name).selectable(false).sense(Sense::click()))
.clicked()
{
let canonicalized = dunce::canonicalize(path.clone()).unwrap_or(path);
let mut proceed = true;
if komorebi_client::send_message(&SocketMessage::ReplaceConfiguration(
canonicalized,
))
.is_err()
{
tracing::error!(
"could not send message to komorebi: ReplaceConfiguration"
);
proceed = false;
}
let canonicalized = dunce::canonicalize(path.clone()).unwrap_or(path);
let mut proceed = true;
if komorebi_client::send_message(&SocketMessage::ReplaceConfiguration(
canonicalized,
))
.is_err()
{
tracing::error!(
"could not send message to komorebi: ReplaceConfiguration"
);
proceed = false;
}
if let Some(rect) = komorebi_notification_state.work_area_offset {
if proceed {
match komorebi_client::send_query(&SocketMessage::Query(
komorebi_client::StateQuery::FocusedMonitorIndex,
)) {
Ok(idx) => {
if let Ok(monitor_idx) = idx.parse::<usize>() {
if komorebi_client::send_message(
&SocketMessage::MonitorWorkAreaOffset(
monitor_idx,
rect,
),
)
.is_err()
{
tracing::error!(
if let Some(rect) = komorebi_notification_state.work_area_offset {
if proceed {
match komorebi_client::send_query(&SocketMessage::Query(
komorebi_client::StateQuery::FocusedMonitorIndex,
)) {
Ok(idx) => {
if let Ok(monitor_idx) = idx.parse::<usize>() {
if komorebi_client::send_message(
&SocketMessage::MonitorWorkAreaOffset(
monitor_idx,
rect,
),
)
.is_err()
{
tracing::error!(
"could not send message to komorebi: MonitorWorkAreaOffset"
);
}
}
}
}
Err(_) => {
tracing::error!(
"could not send message to komorebi: Query"
);
Err(_) => {
tracing::error!(
"could not send message to komorebi: Query"
);
}
}
}
}
}
}});
}
}
ui.add_space(WIDGET_SPACING);
}
}
if let Some(focused_window) = self.focused_window {
if focused_window.enable {
let titles = &komorebi_notification_state.focused_container_information.0;
let icons = &komorebi_notification_state.focused_container_information.1;
let focused_window_idx =
komorebi_notification_state.focused_container_information.2;
if !titles.is_empty() {
config.apply_on_widget(true, ui, |ui| {
let icons = &komorebi_notification_state.focused_container_information.1;
let focused_window_idx =
komorebi_notification_state.focused_container_information.2;
let iter = titles.iter().zip(icons.iter());
let iter = titles.iter().zip(icons.iter());
for (i, (title, icon)) in iter.enumerate() {
if focused_window.show_icon {
if let Some(img) = icon {
ui.add(
Image::from(&img_to_texture(ctx, img))
.maintain_aspect_ratio(true)
.max_height(15.0),
);
}
}
if i == focused_window_idx {
let font_id = ctx
.style()
.text_styles
.get(&TextStyle::Body)
.cloned()
.unwrap_or_else(FontId::default);
let layout_job = LayoutJob::simple(
title.to_string(),
font_id.clone(),
komorebi_notification_state
.stack_accent
.unwrap_or(ctx.style().visuals.selection.stroke.color),
100.0,
);
if titles.len() > 1 {
let available_height = ui.available_height();
let mut custom_ui = CustomUi(ui);
custom_ui.add_sized_left_to_right(
Vec2::new(
MAX_LABEL_WIDTH.load(Ordering::SeqCst) as f32,
available_height,
),
Label::new(layout_job).selectable(false).truncate(),
);
} else {
let available_height = ui.available_height();
let mut custom_ui = CustomUi(ui);
custom_ui.add_sized_left_to_right(
Vec2::new(
MAX_LABEL_WIDTH.load(Ordering::SeqCst) as f32,
available_height,
),
Label::new(title).selectable(false).truncate(),
);
}
} else {
let available_height = ui.available_height();
let mut custom_ui = CustomUi(ui);
if custom_ui
.add_sized_left_to_right(
Vec2::new(
MAX_LABEL_WIDTH.load(Ordering::SeqCst) as f32,
available_height,
),
Label::new(title)
.selectable(false)
.sense(Sense::click())
.truncate(),
)
.clicked()
{
if komorebi_client::send_message(&SocketMessage::MouseFollowsFocus(
false,
))
.is_err()
{
tracing::error!(
"could not send message to komorebi: MouseFollowsFocus"
);
for (i, (title, icon)) in iter.enumerate() {
if focused_window.show_icon {
if let Some(img) = icon {
ui.add(
Image::from(&img_to_texture(ctx, img))
.maintain_aspect_ratio(true)
.max_height(15.0),
);
}
}
if komorebi_client::send_message(&SocketMessage::FocusStackWindow(i))
.is_err()
{
tracing::error!(
"could not send message to komorebi: FocusStackWindow"
);
}
if i == focused_window_idx {
let font_id = ctx
.style()
.text_styles
.get(&TextStyle::Body)
.cloned()
.unwrap_or_else(FontId::default);
if komorebi_client::send_message(&SocketMessage::MouseFollowsFocus(
komorebi_notification_state.mouse_follows_focus,
))
.is_err()
{
tracing::error!(
"could not send message to komorebi: MouseFollowsFocus"
let layout_job = LayoutJob::simple(
title.to_string(),
font_id.clone(),
komorebi_notification_state
.stack_accent
.unwrap_or(ctx.style().visuals.selection.stroke.color),
100.0,
);
if titles.len() > 1 {
let available_height = ui.available_height();
let mut custom_ui = CustomUi(ui);
custom_ui.add_sized_left_to_right(
Vec2::new(
MAX_LABEL_WIDTH.load(Ordering::SeqCst) as f32,
available_height,
),
Label::new(layout_job).selectable(false).truncate(),
);
} else {
let available_height = ui.available_height();
let mut custom_ui = CustomUi(ui);
custom_ui.add_sized_left_to_right(
Vec2::new(
MAX_LABEL_WIDTH.load(Ordering::SeqCst) as f32,
available_height,
),
Label::new(title).selectable(false).truncate(),
);
}
} else {
let available_height = ui.available_height();
let mut custom_ui = CustomUi(ui);
if custom_ui
.add_sized_left_to_right(
Vec2::new(
MAX_LABEL_WIDTH.load(Ordering::SeqCst) as f32,
available_height,
),
Label::new(title)
.selectable(false)
.sense(Sense::click())
.truncate(),
)
.clicked()
{
if komorebi_client::send_message(
&SocketMessage::MouseFollowsFocus(false),
)
.is_err()
{
tracing::error!(
"could not send message to komorebi: MouseFollowsFocus"
);
}
if komorebi_client::send_message(
&SocketMessage::FocusStackWindow(i),
)
.is_err()
{
tracing::error!(
"could not send message to komorebi: FocusStackWindow"
);
}
if komorebi_client::send_message(
&SocketMessage::MouseFollowsFocus(
komorebi_notification_state.mouse_follows_focus,
),
)
.is_err()
{
tracing::error!(
"could not send message to komorebi: MouseFollowsFocus"
);
}
}
}
}
}
ui.add_space(WIDGET_SPACING);
});
}
}
ui.add_space(WIDGET_SPACING);
}
}
}