From 3720ce42d070f7698ba100ba3cccf27c35ed5682 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sat, 21 Sep 2024 10:20:26 -0700 Subject: [PATCH] fix(bar): use truncated labels for titles This commit introduces a new wrapper, CustomUi, which is used to implement custom methods on top of eframe::egui::Ui. The default ui::add_sized method always has the text in a label centered, which is not desirable for a status bar where the layout should be ltr. A new function CustomUi::add_sized_left_to_right has been added to ensure that labels can be truncated with a custom width (which requires allocate_ui_with_layout), while also retaining the ability for the text to be aligned to the left rather than the center of the allocated layout. --- komorebi-bar/src/bar.rs | 7 +++ komorebi-bar/src/config.rs | 2 + komorebi-bar/src/komorebi.rs | 86 ++++++++++++++++++++++++++---------- komorebi-bar/src/main.rs | 3 ++ komorebi-bar/src/media.rs | 15 ++++++- komorebi-bar/src/ui.rs | 22 +++++++++ schema.bar.json | 5 +++ 7 files changed, 114 insertions(+), 26 deletions(-) create mode 100644 komorebi-bar/src/ui.rs diff --git a/komorebi-bar/src/bar.rs b/komorebi-bar/src/bar.rs index 0def1435..ee6e61bd 100644 --- a/komorebi-bar/src/bar.rs +++ b/komorebi-bar/src/bar.rs @@ -4,6 +4,7 @@ use crate::komorebi::Komorebi; use crate::komorebi::KomorebiNotificationState; use crate::widget::BarWidget; use crate::widget::WidgetConfig; +use crate::MAX_LABEL_WIDTH; use crossbeam_channel::Receiver; use eframe::egui::Align; use eframe::egui::CentralPanel; @@ -30,6 +31,7 @@ use komorebi_themes::CatppuccinValue; use std::cell::RefCell; use std::path::PathBuf; use std::rc::Rc; +use std::sync::atomic::Ordering; use std::sync::Arc; pub struct Komobar { @@ -132,6 +134,11 @@ impl Komobar { config: &KomobarConfig, previous_notification_state: Option>>, ) { + MAX_LABEL_WIDTH.store( + config.max_label_width.unwrap_or(400.0) as i32, + Ordering::SeqCst, + ); + if let Some(font_family) = &config.font_family { tracing::info!("attempting to add custom font family: {font_family}"); Self::add_custom_font(ctx, font_family); diff --git a/komorebi-bar/src/config.rs b/komorebi-bar/src/config.rs index 07ff5be0..255edfc8 100644 --- a/komorebi-bar/src/config.rs +++ b/komorebi-bar/src/config.rs @@ -21,6 +21,8 @@ pub struct KomobarConfig { pub font_family: Option, /// Font size (default: 12.5) pub font_size: Option, + /// Max label width before text truncation (default: 400.0) + pub max_label_width: Option, /// Theme pub theme: Option, /// Left side widgets (ordered left-to-right) diff --git a/komorebi-bar/src/komorebi.rs b/komorebi-bar/src/komorebi.rs index bc221eee..22b942e4 100644 --- a/komorebi-bar/src/komorebi.rs +++ b/komorebi-bar/src/komorebi.rs @@ -1,6 +1,8 @@ use crate::bar::apply_theme; use crate::config::KomobarTheme; +use crate::ui::CustomUi; use crate::widget::BarWidget; +use crate::MAX_LABEL_WIDTH; use crate::WIDGET_SPACING; use crossbeam_channel::Receiver; use eframe::egui::text::LayoutJob; @@ -16,6 +18,7 @@ use eframe::egui::TextStyle; use eframe::egui::TextureHandle; use eframe::egui::TextureOptions; use eframe::egui::Ui; +use eframe::egui::Vec2; use image::RgbaImage; use komorebi_client::CycleDirection; use komorebi_client::NotificationEvent; @@ -28,6 +31,7 @@ use std::cell::RefCell; use std::collections::BTreeMap; use std::path::PathBuf; use std::rc::Rc; +use std::sync::atomic::Ordering; #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] pub struct KomorebiConfig { @@ -295,36 +299,70 @@ impl BarWidget for Komorebi { ); if titles.len() > 1 { - ui.add(Label::new(layout_job).selectable(false)); + 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 { - ui.add(Label::new(title).selectable(false)); - } - } else if ui - .add(Label::new(title).selectable(false).sense(Sense::click())) - .clicked() - { - if komorebi_client::send_message(&SocketMessage::MouseFollowsFocus(false)) - .is_err() - { - tracing::error!( - "could not send message to komorebi: MouseFollowsFocus" + 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 komorebi_client::send_message(&SocketMessage::FocusStackWindow(i)) + 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: FocusStackWindow"); - } + { + tracing::error!( + "could not send message to komorebi: MouseFollowsFocus" + ); + } - if komorebi_client::send_message(&SocketMessage::MouseFollowsFocus( - komorebi_notification_state.mouse_follows_focus, - )) - .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" + ); + } } } diff --git a/komorebi-bar/src/main.rs b/komorebi-bar/src/main.rs index 7fb12492..fea08029 100644 --- a/komorebi-bar/src/main.rs +++ b/komorebi-bar/src/main.rs @@ -8,6 +8,7 @@ mod memory; mod network; mod storage; mod time; +mod ui; mod widget; use crate::bar::Komobar; @@ -24,11 +25,13 @@ use schemars::gen::SchemaSettings; use std::io::BufReader; use std::io::Read; use std::path::PathBuf; +use std::sync::atomic::AtomicI32; use std::sync::Arc; use std::time::Duration; use tracing_subscriber::EnvFilter; pub static WIDGET_SPACING: f32 = 10.0; +pub static MAX_LABEL_WIDTH: AtomicI32 = AtomicI32::new(400); #[derive(Parser)] #[clap(author, about, version)] diff --git a/komorebi-bar/src/media.rs b/komorebi-bar/src/media.rs index f88b181b..23f8f959 100644 --- a/komorebi-bar/src/media.rs +++ b/komorebi-bar/src/media.rs @@ -1,4 +1,6 @@ +use crate::ui::CustomUi; use crate::widget::BarWidget; +use crate::MAX_LABEL_WIDTH; use crate::WIDGET_SPACING; use eframe::egui::text::LayoutJob; use eframe::egui::Context; @@ -8,9 +10,11 @@ use eframe::egui::Sense; use eframe::egui::TextFormat; use eframe::egui::TextStyle; use eframe::egui::Ui; +use eframe::egui::Vec2; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; +use std::sync::atomic::Ordering; use windows::Media::Control::GlobalSystemMediaTransportControlsSessionManager; #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] @@ -98,8 +102,15 @@ impl BarWidget for Media { TextFormat::simple(font_id, ctx.style().visuals.text_color()), ); - if ui - .add( + 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(layout_job) .selectable(false) .sense(Sense::click()) diff --git a/komorebi-bar/src/ui.rs b/komorebi-bar/src/ui.rs new file mode 100644 index 00000000..24d58444 --- /dev/null +++ b/komorebi-bar/src/ui.rs @@ -0,0 +1,22 @@ +use eframe::egui::Align; +use eframe::egui::Layout; +use eframe::egui::Response; +use eframe::egui::Ui; +use eframe::egui::Vec2; +use eframe::egui::Widget; + +pub struct CustomUi<'ui>(pub &'ui mut Ui); + +impl CustomUi<'_> { + pub fn add_sized_left_to_right( + &mut self, + max_size: impl Into, + widget: impl Widget, + ) -> Response { + let layout = + Layout::from_main_dir_and_cross_align(self.0.layout().main_dir(), Align::Center); + self.0 + .allocate_ui_with_layout(max_size.into(), layout, |ui| ui.add(widget)) + .inner + } +} diff --git a/schema.bar.json b/schema.bar.json index 2b97bcc3..a591e5ad 100644 --- a/schema.bar.json +++ b/schema.bar.json @@ -408,6 +408,11 @@ ] } }, + "max_label_width": { + "description": "Max label width before text truncation (default: 400.0)", + "type": "number", + "format": "float" + }, "monitor": { "description": "Monitor options", "type": "object",