mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-04-17 22:39:46 +02:00
feat(bar): auto select/hide widget based on value
This commit adds new settings to some widgets that allows to auto select/hide them based on their current values. The cpu/memory/network/storage widgets get a setting that auto selects the widget if the current value/percentage is over a value. The battery widget gets a setting that auto selects the widget if the current percentage is under a value. The storage widget gets a setting that auto hides the disk widget if the percentage is under a value. Also added 2 new settings (auto_select_fill and auto_select_text) to the theme, in order to select the fill and text colors of an auto selected widget. (Easter egg: the network icons change if the value is over the limit) PR: #1353
This commit is contained in:
@@ -14,6 +14,8 @@ use crate::widgets::komorebi::KomorebiNotificationState;
|
|||||||
use crate::widgets::widget::BarWidget;
|
use crate::widgets::widget::BarWidget;
|
||||||
use crate::widgets::widget::WidgetConfig;
|
use crate::widgets::widget::WidgetConfig;
|
||||||
use crate::KomorebiEvent;
|
use crate::KomorebiEvent;
|
||||||
|
use crate::AUTO_SELECT_FILL_COLOUR;
|
||||||
|
use crate::AUTO_SELECT_TEXT_COLOUR;
|
||||||
use crate::BAR_HEIGHT;
|
use crate::BAR_HEIGHT;
|
||||||
use crate::DEFAULT_PADDING;
|
use crate::DEFAULT_PADDING;
|
||||||
use crate::MAX_LABEL_WIDTH;
|
use crate::MAX_LABEL_WIDTH;
|
||||||
@@ -43,6 +45,7 @@ use eframe::egui::Vec2;
|
|||||||
use eframe::egui::Visuals;
|
use eframe::egui::Visuals;
|
||||||
use font_loader::system_fonts;
|
use font_loader::system_fonts;
|
||||||
use font_loader::system_fonts::FontPropertyBuilder;
|
use font_loader::system_fonts::FontPropertyBuilder;
|
||||||
|
use komorebi_client::Colour;
|
||||||
use komorebi_client::KomorebiTheme;
|
use komorebi_client::KomorebiTheme;
|
||||||
use komorebi_client::MonitorNotification;
|
use komorebi_client::MonitorNotification;
|
||||||
use komorebi_client::NotificationEvent;
|
use komorebi_client::NotificationEvent;
|
||||||
@@ -88,71 +91,82 @@ pub fn apply_theme(
|
|||||||
grouping: Option<Grouping>,
|
grouping: Option<Grouping>,
|
||||||
render_config: Rc<RefCell<RenderConfig>>,
|
render_config: Rc<RefCell<RenderConfig>>,
|
||||||
) {
|
) {
|
||||||
match theme {
|
let (auto_select_fill, auto_select_text) = match theme {
|
||||||
KomobarTheme::Catppuccin {
|
KomobarTheme::Catppuccin {
|
||||||
name: catppuccin,
|
name: catppuccin,
|
||||||
accent: catppuccin_value,
|
accent: catppuccin_value,
|
||||||
} => match catppuccin {
|
auto_select_fill: catppuccin_auto_select_fill,
|
||||||
Catppuccin::Frappe => {
|
auto_select_text: catppuccin_auto_select_text,
|
||||||
catppuccin_egui::set_theme(ctx, catppuccin_egui::FRAPPE);
|
} => {
|
||||||
let catppuccin_value = catppuccin_value.unwrap_or_default();
|
match catppuccin {
|
||||||
let accent = catppuccin_value.color32(catppuccin.as_theme());
|
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| {
|
ctx.style_mut(|style| {
|
||||||
style.visuals.selection.stroke.color = accent;
|
style.visuals.selection.stroke.color = accent;
|
||||||
style.visuals.widgets.hovered.fg_stroke.color = accent;
|
style.visuals.widgets.hovered.fg_stroke.color = accent;
|
||||||
style.visuals.widgets.active.fg_stroke.color = accent;
|
style.visuals.widgets.active.fg_stroke.color = accent;
|
||||||
style.visuals.override_text_color = None;
|
style.visuals.override_text_color = None;
|
||||||
});
|
});
|
||||||
|
|
||||||
bg_color.replace(catppuccin_egui::FRAPPE.base);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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;
|
catppuccin_auto_select_fill.map(|c| c.color32(catppuccin.as_theme())),
|
||||||
style.visuals.widgets.hovered.fg_stroke.color = accent;
|
catppuccin_auto_select_text.map(|c| c.color32(catppuccin.as_theme())),
|
||||||
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 {
|
KomobarTheme::Base16 {
|
||||||
name: base16,
|
name: base16,
|
||||||
accent: base16_value,
|
accent: base16_value,
|
||||||
|
auto_select_fill: base16_auto_select_fill,
|
||||||
|
auto_select_text: base16_auto_select_text,
|
||||||
} => {
|
} => {
|
||||||
ctx.set_style(base16.style());
|
ctx.set_style(base16.style());
|
||||||
let base16_value = base16_value.unwrap_or_default();
|
let base16_value = base16_value.unwrap_or_default();
|
||||||
@@ -165,15 +179,22 @@ pub fn apply_theme(
|
|||||||
});
|
});
|
||||||
|
|
||||||
bg_color.replace(base16.background());
|
bg_color.replace(base16.background());
|
||||||
|
|
||||||
|
(
|
||||||
|
base16_auto_select_fill.map(|c| c.color32(Base16Wrapper::Base16(base16))),
|
||||||
|
base16_auto_select_text.map(|c| c.color32(Base16Wrapper::Base16(base16))),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
KomobarTheme::Custom {
|
KomobarTheme::Custom {
|
||||||
colours,
|
colours,
|
||||||
accent: base16_value,
|
accent: base16_value,
|
||||||
|
auto_select_fill: base16_auto_select_fill,
|
||||||
|
auto_select_text: base16_auto_select_text,
|
||||||
} => {
|
} => {
|
||||||
let background = colours.background();
|
let background = colours.background();
|
||||||
ctx.set_style(colours.style());
|
ctx.set_style(colours.style());
|
||||||
let base16_value = base16_value.unwrap_or_default();
|
let base16_value = base16_value.unwrap_or_default();
|
||||||
let accent = base16_value.color32(Base16Wrapper::Custom(colours));
|
let accent = base16_value.color32(Base16Wrapper::Custom(colours.clone()));
|
||||||
|
|
||||||
ctx.style_mut(|style| {
|
ctx.style_mut(|style| {
|
||||||
style.visuals.selection.stroke.color = accent;
|
style.visuals.selection.stroke.color = accent;
|
||||||
@@ -182,8 +203,22 @@ pub fn apply_theme(
|
|||||||
});
|
});
|
||||||
|
|
||||||
bg_color.replace(background);
|
bg_color.replace(background);
|
||||||
|
|
||||||
|
(
|
||||||
|
base16_auto_select_fill.map(|c| c.color32(Base16Wrapper::Custom(colours.clone()))),
|
||||||
|
base16_auto_select_text.map(|c| c.color32(Base16Wrapper::Custom(colours.clone()))),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
AUTO_SELECT_FILL_COLOUR.store(
|
||||||
|
auto_select_fill.map_or(0, |c| Colour::from(c).into()),
|
||||||
|
Ordering::SeqCst,
|
||||||
|
);
|
||||||
|
AUTO_SELECT_TEXT_COLOUR.store(
|
||||||
|
auto_select_text.map_or(0, |c| Colour::from(c).into()),
|
||||||
|
Ordering::SeqCst,
|
||||||
|
);
|
||||||
|
|
||||||
// Apply transparency_alpha
|
// Apply transparency_alpha
|
||||||
let theme_color = *bg_color.borrow();
|
let theme_color = *bg_color.borrow();
|
||||||
|
|||||||
@@ -382,18 +382,24 @@ pub enum KomobarTheme {
|
|||||||
/// Name of the Catppuccin theme (theme previews: https://github.com/catppuccin/catppuccin)
|
/// Name of the Catppuccin theme (theme previews: https://github.com/catppuccin/catppuccin)
|
||||||
name: komorebi_themes::Catppuccin,
|
name: komorebi_themes::Catppuccin,
|
||||||
accent: Option<komorebi_themes::CatppuccinValue>,
|
accent: Option<komorebi_themes::CatppuccinValue>,
|
||||||
|
auto_select_fill: Option<komorebi_themes::CatppuccinValue>,
|
||||||
|
auto_select_text: Option<komorebi_themes::CatppuccinValue>,
|
||||||
},
|
},
|
||||||
/// A theme from base16-egui-themes
|
/// A theme from base16-egui-themes
|
||||||
Base16 {
|
Base16 {
|
||||||
/// Name of the Base16 theme (theme previews: https://tinted-theming.github.io/tinted-gallery/)
|
/// Name of the Base16 theme (theme previews: https://tinted-theming.github.io/tinted-gallery/)
|
||||||
name: komorebi_themes::Base16,
|
name: komorebi_themes::Base16,
|
||||||
accent: Option<komorebi_themes::Base16Value>,
|
accent: Option<komorebi_themes::Base16Value>,
|
||||||
|
auto_select_fill: Option<komorebi_themes::Base16Value>,
|
||||||
|
auto_select_text: Option<komorebi_themes::Base16Value>,
|
||||||
},
|
},
|
||||||
/// A custom Base16 theme
|
/// A custom Base16 theme
|
||||||
Custom {
|
Custom {
|
||||||
/// Colours of the custom Base16 theme palette
|
/// Colours of the custom Base16 theme palette
|
||||||
colours: Box<komorebi_themes::Base16ColourPalette>,
|
colours: Box<komorebi_themes::Base16ColourPalette>,
|
||||||
accent: Option<komorebi_themes::Base16Value>,
|
accent: Option<komorebi_themes::Base16Value>,
|
||||||
|
auto_select_fill: Option<komorebi_themes::Base16Value>,
|
||||||
|
auto_select_text: Option<komorebi_themes::Base16Value>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,12 +411,16 @@ impl From<KomorebiTheme> for KomobarTheme {
|
|||||||
} => Self::Catppuccin {
|
} => Self::Catppuccin {
|
||||||
name,
|
name,
|
||||||
accent: bar_accent,
|
accent: bar_accent,
|
||||||
|
auto_select_fill: None,
|
||||||
|
auto_select_text: None,
|
||||||
},
|
},
|
||||||
KomorebiTheme::Base16 {
|
KomorebiTheme::Base16 {
|
||||||
name, bar_accent, ..
|
name, bar_accent, ..
|
||||||
} => Self::Base16 {
|
} => Self::Base16 {
|
||||||
name,
|
name,
|
||||||
accent: bar_accent,
|
accent: bar_accent,
|
||||||
|
auto_select_fill: None,
|
||||||
|
auto_select_text: None,
|
||||||
},
|
},
|
||||||
KomorebiTheme::Custom {
|
KomorebiTheme::Custom {
|
||||||
colours,
|
colours,
|
||||||
@@ -419,6 +429,8 @@ impl From<KomorebiTheme> for KomobarTheme {
|
|||||||
} => Self::Custom {
|
} => Self::Custom {
|
||||||
colours,
|
colours,
|
||||||
accent: bar_accent,
|
accent: bar_accent,
|
||||||
|
auto_select_fill: None,
|
||||||
|
auto_select_text: None,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ use std::io::BufReader;
|
|||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::atomic::AtomicI32;
|
use std::sync::atomic::AtomicI32;
|
||||||
|
use std::sync::atomic::AtomicU32;
|
||||||
use std::sync::atomic::AtomicUsize;
|
use std::sync::atomic::AtomicUsize;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
@@ -47,6 +48,9 @@ pub static MONITOR_INDEX: AtomicUsize = AtomicUsize::new(0);
|
|||||||
pub static BAR_HEIGHT: f32 = 50.0;
|
pub static BAR_HEIGHT: f32 = 50.0;
|
||||||
pub static DEFAULT_PADDING: f32 = 10.0;
|
pub static DEFAULT_PADDING: f32 = 10.0;
|
||||||
|
|
||||||
|
pub static AUTO_SELECT_FILL_COLOUR: AtomicU32 = AtomicU32::new(0);
|
||||||
|
pub static AUTO_SELECT_TEXT_COLOUR: AtomicU32 = AtomicU32::new(0);
|
||||||
|
|
||||||
pub static ICON_CACHE: LazyLock<Mutex<HashMap<isize, RgbaImage>>> =
|
pub static ICON_CACHE: LazyLock<Mutex<HashMap<isize, RgbaImage>>> =
|
||||||
LazyLock::new(|| Mutex::new(HashMap::new()));
|
LazyLock::new(|| Mutex::new(HashMap::new()));
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
use crate::bar::Alignment;
|
use crate::bar::Alignment;
|
||||||
use crate::config::KomobarConfig;
|
use crate::config::KomobarConfig;
|
||||||
use crate::config::MonitorConfigOrIndex;
|
use crate::config::MonitorConfigOrIndex;
|
||||||
|
use crate::AUTO_SELECT_FILL_COLOUR;
|
||||||
|
use crate::AUTO_SELECT_TEXT_COLOUR;
|
||||||
use eframe::egui::Color32;
|
use eframe::egui::Color32;
|
||||||
use eframe::egui::Context;
|
use eframe::egui::Context;
|
||||||
use eframe::egui::CornerRadius;
|
use eframe::egui::CornerRadius;
|
||||||
@@ -11,8 +13,11 @@ use eframe::egui::Margin;
|
|||||||
use eframe::egui::Shadow;
|
use eframe::egui::Shadow;
|
||||||
use eframe::egui::TextStyle;
|
use eframe::egui::TextStyle;
|
||||||
use eframe::egui::Ui;
|
use eframe::egui::Ui;
|
||||||
|
use komorebi_client::Colour;
|
||||||
|
use komorebi_client::Rgb;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use std::num::NonZeroU32;
|
||||||
use std::sync::atomic::AtomicUsize;
|
use std::sync::atomic::AtomicUsize;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -55,6 +60,10 @@ pub struct RenderConfig {
|
|||||||
pub icon_font_id: FontId,
|
pub icon_font_id: FontId,
|
||||||
/// Show all icons on the workspace section of the Komorebi widget
|
/// Show all icons on the workspace section of the Komorebi widget
|
||||||
pub show_all_icons: bool,
|
pub show_all_icons: bool,
|
||||||
|
/// Background color of the selected frame
|
||||||
|
pub auto_select_fill: Option<Color32>,
|
||||||
|
/// Text color of the selected frame
|
||||||
|
pub auto_select_text: Option<Color32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait RenderExt {
|
pub trait RenderExt {
|
||||||
@@ -108,6 +117,10 @@ impl RenderExt for &KomobarConfig {
|
|||||||
text_font_id,
|
text_font_id,
|
||||||
icon_font_id,
|
icon_font_id,
|
||||||
show_all_icons,
|
show_all_icons,
|
||||||
|
auto_select_fill: NonZeroU32::new(AUTO_SELECT_FILL_COLOUR.load(Ordering::SeqCst))
|
||||||
|
.map(|c| Colour::Rgb(Rgb::from(c.get())).into()),
|
||||||
|
auto_select_text: NonZeroU32::new(AUTO_SELECT_TEXT_COLOUR.load(Ordering::SeqCst))
|
||||||
|
.map(|c| Colour::Rgb(Rgb::from(c.get())).into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,6 +146,8 @@ impl RenderConfig {
|
|||||||
text_font_id: FontId::default(),
|
text_font_id: FontId::default(),
|
||||||
icon_font_id: FontId::default(),
|
icon_font_id: FontId::default(),
|
||||||
show_all_icons: false,
|
show_all_icons: false,
|
||||||
|
auto_select_fill: None,
|
||||||
|
auto_select_text: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,15 +10,29 @@ use eframe::egui::Ui;
|
|||||||
/// Same as SelectableLabel, but supports all content
|
/// Same as SelectableLabel, but supports all content
|
||||||
pub struct SelectableFrame {
|
pub struct SelectableFrame {
|
||||||
selected: bool,
|
selected: bool,
|
||||||
|
selected_fill: Option<Color32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SelectableFrame {
|
impl SelectableFrame {
|
||||||
pub fn new(selected: bool) -> Self {
|
pub fn new(selected: bool) -> Self {
|
||||||
Self { selected }
|
Self {
|
||||||
|
selected,
|
||||||
|
selected_fill: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_auto(selected: bool, selected_fill: Option<Color32>) -> Self {
|
||||||
|
Self {
|
||||||
|
selected,
|
||||||
|
selected_fill,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show<R>(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> Response {
|
pub fn show<R>(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> Response {
|
||||||
let Self { selected } = self;
|
let Self {
|
||||||
|
selected,
|
||||||
|
selected_fill,
|
||||||
|
} = self;
|
||||||
|
|
||||||
Frame::NONE
|
Frame::NONE
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
@@ -32,7 +46,16 @@ impl SelectableFrame {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// since the stroke is drawn inside the frame, we always reserve space for it
|
// since the stroke is drawn inside the frame, we always reserve space for it
|
||||||
if response.hovered() || response.highlighted() || response.has_focus() {
|
if selected && response.hovered() {
|
||||||
|
let visuals = ui.style().interact_selectable(&response, selected);
|
||||||
|
|
||||||
|
Frame::NONE
|
||||||
|
.stroke(Stroke::new(1.0, visuals.bg_stroke.color))
|
||||||
|
.corner_radius(visuals.corner_radius)
|
||||||
|
.fill(selected_fill.unwrap_or(visuals.bg_fill))
|
||||||
|
.inner_margin(inner_margin)
|
||||||
|
.show(ui, add_contents);
|
||||||
|
} else if response.hovered() || response.highlighted() || response.has_focus() {
|
||||||
let visuals = ui.style().interact_selectable(&response, selected);
|
let visuals = ui.style().interact_selectable(&response, selected);
|
||||||
|
|
||||||
Frame::NONE
|
Frame::NONE
|
||||||
@@ -47,7 +70,7 @@ impl SelectableFrame {
|
|||||||
Frame::NONE
|
Frame::NONE
|
||||||
.stroke(Stroke::new(1.0, visuals.bg_fill))
|
.stroke(Stroke::new(1.0, visuals.bg_fill))
|
||||||
.corner_radius(visuals.corner_radius)
|
.corner_radius(visuals.corner_radius)
|
||||||
.fill(visuals.bg_fill)
|
.fill(selected_fill.unwrap_or(visuals.bg_fill))
|
||||||
.inner_margin(inner_margin)
|
.inner_margin(inner_margin)
|
||||||
.show(ui, add_contents);
|
.show(ui, add_contents);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ pub struct BatteryConfig {
|
|||||||
pub data_refresh_interval: Option<u64>,
|
pub data_refresh_interval: Option<u64>,
|
||||||
/// Display label prefix
|
/// Display label prefix
|
||||||
pub label_prefix: Option<LabelPrefix>,
|
pub label_prefix: Option<LabelPrefix>,
|
||||||
|
/// Select when the current percentage is under this value [[1-100]]
|
||||||
|
pub auto_select_under: Option<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BatteryConfig> for Battery {
|
impl From<BatteryConfig> for Battery {
|
||||||
@@ -38,9 +40,10 @@ impl From<BatteryConfig> for Battery {
|
|||||||
enable: value.enable,
|
enable: value.enable,
|
||||||
hide_on_full_charge: value.hide_on_full_charge.unwrap_or(false),
|
hide_on_full_charge: value.hide_on_full_charge.unwrap_or(false),
|
||||||
manager: Manager::new().unwrap(),
|
manager: Manager::new().unwrap(),
|
||||||
last_state: String::new(),
|
last_state: None,
|
||||||
data_refresh_interval,
|
data_refresh_interval,
|
||||||
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon),
|
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon),
|
||||||
|
auto_select_under: value.auto_select_under.map(|u| u.clamp(1, 100)),
|
||||||
state: BatteryState::Discharging,
|
state: BatteryState::Discharging,
|
||||||
last_updated: Instant::now()
|
last_updated: Instant::now()
|
||||||
.checked_sub(Duration::from_secs(data_refresh_interval))
|
.checked_sub(Duration::from_secs(data_refresh_interval))
|
||||||
@@ -54,6 +57,12 @@ pub enum BatteryState {
|
|||||||
Discharging,
|
Discharging,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct BatteryOutput {
|
||||||
|
label: String,
|
||||||
|
selected: bool,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Battery {
|
pub struct Battery {
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
hide_on_full_charge: bool,
|
hide_on_full_charge: bool,
|
||||||
@@ -61,24 +70,25 @@ pub struct Battery {
|
|||||||
pub state: BatteryState,
|
pub state: BatteryState,
|
||||||
data_refresh_interval: u64,
|
data_refresh_interval: u64,
|
||||||
label_prefix: LabelPrefix,
|
label_prefix: LabelPrefix,
|
||||||
last_state: String,
|
auto_select_under: Option<u8>,
|
||||||
|
last_state: Option<BatteryOutput>,
|
||||||
last_updated: Instant,
|
last_updated: Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Battery {
|
impl Battery {
|
||||||
fn output(&mut self) -> String {
|
fn output(&mut self) -> Option<BatteryOutput> {
|
||||||
let mut output = self.last_state.clone();
|
let mut output = self.last_state.clone();
|
||||||
|
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) {
|
if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) {
|
||||||
output.clear();
|
output = None;
|
||||||
|
|
||||||
if let Ok(mut batteries) = self.manager.batteries() {
|
if let Ok(mut batteries) = self.manager.batteries() {
|
||||||
if let Some(Ok(first)) = batteries.nth(0) {
|
if let Some(Ok(first)) = batteries.nth(0) {
|
||||||
let percentage = first.state_of_charge().get::<percent>();
|
let percentage = first.state_of_charge().get::<percent>() as u8;
|
||||||
|
|
||||||
if percentage == 100.0 && self.hide_on_full_charge {
|
if percentage == 100 && self.hide_on_full_charge {
|
||||||
output = String::new()
|
output = None
|
||||||
} else {
|
} else {
|
||||||
match first.state() {
|
match first.state() {
|
||||||
State::Charging => self.state = BatteryState::Charging,
|
State::Charging => self.state = BatteryState::Charging,
|
||||||
@@ -86,12 +96,19 @@ impl Battery {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
output = match self.label_prefix {
|
let selected = self.auto_select_under.is_some_and(|u| percentage <= u);
|
||||||
LabelPrefix::Text | LabelPrefix::IconAndText => {
|
|
||||||
format!("BAT: {percentage:.0}%")
|
output = Some(BatteryOutput {
|
||||||
}
|
label: match self.label_prefix {
|
||||||
LabelPrefix::None | LabelPrefix::Icon => format!("{percentage:.0}%"),
|
LabelPrefix::Text | LabelPrefix::IconAndText => {
|
||||||
}
|
format!("BAT: {percentage}%")
|
||||||
|
}
|
||||||
|
LabelPrefix::None | LabelPrefix::Icon => {
|
||||||
|
format!("{percentage}%")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selected,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,35 +125,39 @@ impl BarWidget for Battery {
|
|||||||
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
|
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
|
||||||
if self.enable {
|
if self.enable {
|
||||||
let output = self.output();
|
let output = self.output();
|
||||||
if !output.is_empty() {
|
if let Some(output) = output {
|
||||||
let emoji = match self.state {
|
let emoji = match self.state {
|
||||||
BatteryState::Charging => egui_phosphor::regular::BATTERY_CHARGING,
|
BatteryState::Charging => egui_phosphor::regular::BATTERY_CHARGING,
|
||||||
BatteryState::Discharging => egui_phosphor::regular::BATTERY_FULL,
|
BatteryState::Discharging => egui_phosphor::regular::BATTERY_FULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let auto_text_color = config.auto_select_text.filter(|_| output.selected);
|
||||||
|
|
||||||
let mut layout_job = LayoutJob::simple(
|
let mut layout_job = LayoutJob::simple(
|
||||||
match self.label_prefix {
|
match self.label_prefix {
|
||||||
LabelPrefix::Icon | LabelPrefix::IconAndText => emoji.to_string(),
|
LabelPrefix::Icon | LabelPrefix::IconAndText => emoji.to_string(),
|
||||||
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
||||||
},
|
},
|
||||||
config.icon_font_id.clone(),
|
config.icon_font_id.clone(),
|
||||||
ctx.style().visuals.selection.stroke.color,
|
auto_text_color.unwrap_or(ctx.style().visuals.selection.stroke.color),
|
||||||
100.0,
|
100.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
layout_job.append(
|
layout_job.append(
|
||||||
&output,
|
&output.label,
|
||||||
10.0,
|
10.0,
|
||||||
TextFormat {
|
TextFormat {
|
||||||
font_id: config.text_font_id.clone(),
|
font_id: config.text_font_id.clone(),
|
||||||
color: ctx.style().visuals.text_color(),
|
color: auto_text_color.unwrap_or(ctx.style().visuals.text_color()),
|
||||||
valign: Align::Center,
|
valign: Align::Center,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let auto_focus_fill = config.auto_select_fill;
|
||||||
|
|
||||||
config.apply_on_widget(false, ui, |ui| {
|
config.apply_on_widget(false, ui, |ui| {
|
||||||
if SelectableFrame::new(false)
|
if SelectableFrame::new_auto(output.selected, auto_focus_fill)
|
||||||
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
|
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ pub struct CpuConfig {
|
|||||||
pub data_refresh_interval: Option<u64>,
|
pub data_refresh_interval: Option<u64>,
|
||||||
/// Display label prefix
|
/// Display label prefix
|
||||||
pub label_prefix: Option<LabelPrefix>,
|
pub label_prefix: Option<LabelPrefix>,
|
||||||
|
/// Select when the current percentage is over this value [[1-100]]
|
||||||
|
pub auto_select_over: Option<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CpuConfig> for Cpu {
|
impl From<CpuConfig> for Cpu {
|
||||||
@@ -38,6 +40,7 @@ impl From<CpuConfig> for Cpu {
|
|||||||
),
|
),
|
||||||
data_refresh_interval,
|
data_refresh_interval,
|
||||||
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText),
|
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText),
|
||||||
|
auto_select_over: value.auto_select_over.map(|o| o.clamp(1, 100)),
|
||||||
last_updated: Instant::now()
|
last_updated: Instant::now()
|
||||||
.checked_sub(Duration::from_secs(data_refresh_interval))
|
.checked_sub(Duration::from_secs(data_refresh_interval))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
@@ -45,26 +48,38 @@ impl From<CpuConfig> for Cpu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct CpuOutput {
|
||||||
|
label: String,
|
||||||
|
selected: bool,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Cpu {
|
pub struct Cpu {
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
system: System,
|
system: System,
|
||||||
data_refresh_interval: u64,
|
data_refresh_interval: u64,
|
||||||
label_prefix: LabelPrefix,
|
label_prefix: LabelPrefix,
|
||||||
|
auto_select_over: Option<u8>,
|
||||||
last_updated: Instant,
|
last_updated: Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cpu {
|
impl Cpu {
|
||||||
fn output(&mut self) -> String {
|
fn output(&mut self) -> CpuOutput {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) {
|
if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) {
|
||||||
self.system.refresh_cpu_usage();
|
self.system.refresh_cpu_usage();
|
||||||
self.last_updated = now;
|
self.last_updated = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
let used = self.system.global_cpu_usage();
|
let used = self.system.global_cpu_usage() as u8;
|
||||||
match self.label_prefix {
|
let selected = self.auto_select_over.is_some_and(|o| used >= o);
|
||||||
LabelPrefix::Text | LabelPrefix::IconAndText => format!("CPU: {:.0}%", used),
|
|
||||||
LabelPrefix::None | LabelPrefix::Icon => format!("{:.0}%", used),
|
CpuOutput {
|
||||||
|
label: match self.label_prefix {
|
||||||
|
LabelPrefix::Text | LabelPrefix::IconAndText => format!("CPU: {}%", used),
|
||||||
|
LabelPrefix::None | LabelPrefix::Icon => format!("{}%", used),
|
||||||
|
},
|
||||||
|
selected,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,7 +88,9 @@ impl BarWidget for Cpu {
|
|||||||
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
|
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
|
||||||
if self.enable {
|
if self.enable {
|
||||||
let output = self.output();
|
let output = self.output();
|
||||||
if !output.is_empty() {
|
if !output.label.is_empty() {
|
||||||
|
let auto_text_color = config.auto_select_text.filter(|_| output.selected);
|
||||||
|
|
||||||
let mut layout_job = LayoutJob::simple(
|
let mut layout_job = LayoutJob::simple(
|
||||||
match self.label_prefix {
|
match self.label_prefix {
|
||||||
LabelPrefix::Icon | LabelPrefix::IconAndText => {
|
LabelPrefix::Icon | LabelPrefix::IconAndText => {
|
||||||
@@ -82,23 +99,25 @@ impl BarWidget for Cpu {
|
|||||||
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
||||||
},
|
},
|
||||||
config.icon_font_id.clone(),
|
config.icon_font_id.clone(),
|
||||||
ctx.style().visuals.selection.stroke.color,
|
auto_text_color.unwrap_or(ctx.style().visuals.selection.stroke.color),
|
||||||
100.0,
|
100.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
layout_job.append(
|
layout_job.append(
|
||||||
&output,
|
&output.label,
|
||||||
10.0,
|
10.0,
|
||||||
TextFormat {
|
TextFormat {
|
||||||
font_id: config.text_font_id.clone(),
|
font_id: config.text_font_id.clone(),
|
||||||
color: ctx.style().visuals.text_color(),
|
color: auto_text_color.unwrap_or(ctx.style().visuals.text_color()),
|
||||||
valign: Align::Center,
|
valign: Align::Center,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let auto_focus_fill = config.auto_select_fill;
|
||||||
|
|
||||||
config.apply_on_widget(false, ui, |ui| {
|
config.apply_on_widget(false, ui, |ui| {
|
||||||
if SelectableFrame::new(false)
|
if SelectableFrame::new_auto(output.selected, auto_focus_fill)
|
||||||
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
|
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ pub struct MemoryConfig {
|
|||||||
pub data_refresh_interval: Option<u64>,
|
pub data_refresh_interval: Option<u64>,
|
||||||
/// Display label prefix
|
/// Display label prefix
|
||||||
pub label_prefix: Option<LabelPrefix>,
|
pub label_prefix: Option<LabelPrefix>,
|
||||||
|
/// Select when the current percentage is over this value [[1-100]]
|
||||||
|
pub auto_select_over: Option<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<MemoryConfig> for Memory {
|
impl From<MemoryConfig> for Memory {
|
||||||
@@ -38,6 +40,7 @@ impl From<MemoryConfig> for Memory {
|
|||||||
),
|
),
|
||||||
data_refresh_interval,
|
data_refresh_interval,
|
||||||
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText),
|
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText),
|
||||||
|
auto_select_over: value.auto_select_over.map(|o| o.clamp(1, 100)),
|
||||||
last_updated: Instant::now()
|
last_updated: Instant::now()
|
||||||
.checked_sub(Duration::from_secs(data_refresh_interval))
|
.checked_sub(Duration::from_secs(data_refresh_interval))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
@@ -45,16 +48,23 @@ impl From<MemoryConfig> for Memory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct MemoryOutput {
|
||||||
|
label: String,
|
||||||
|
selected: bool,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Memory {
|
pub struct Memory {
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
system: System,
|
system: System,
|
||||||
data_refresh_interval: u64,
|
data_refresh_interval: u64,
|
||||||
label_prefix: LabelPrefix,
|
label_prefix: LabelPrefix,
|
||||||
|
auto_select_over: Option<u8>,
|
||||||
last_updated: Instant,
|
last_updated: Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Memory {
|
impl Memory {
|
||||||
fn output(&mut self) -> String {
|
fn output(&mut self) -> MemoryOutput {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) {
|
if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) {
|
||||||
self.system.refresh_memory();
|
self.system.refresh_memory();
|
||||||
@@ -63,11 +73,17 @@ impl Memory {
|
|||||||
|
|
||||||
let used = self.system.used_memory();
|
let used = self.system.used_memory();
|
||||||
let total = self.system.total_memory();
|
let total = self.system.total_memory();
|
||||||
match self.label_prefix {
|
let usage = ((used * 100) / total) as u8;
|
||||||
LabelPrefix::Text | LabelPrefix::IconAndText => {
|
let selected = self.auto_select_over.is_some_and(|o| usage >= o);
|
||||||
format!("RAM: {}%", (used * 100) / total)
|
|
||||||
}
|
MemoryOutput {
|
||||||
LabelPrefix::None | LabelPrefix::Icon => format!("{}%", (used * 100) / total),
|
label: match self.label_prefix {
|
||||||
|
LabelPrefix::Text | LabelPrefix::IconAndText => {
|
||||||
|
format!("RAM: {}%", usage)
|
||||||
|
}
|
||||||
|
LabelPrefix::None | LabelPrefix::Icon => format!("{}%", usage),
|
||||||
|
},
|
||||||
|
selected,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,7 +92,9 @@ impl BarWidget for Memory {
|
|||||||
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
|
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
|
||||||
if self.enable {
|
if self.enable {
|
||||||
let output = self.output();
|
let output = self.output();
|
||||||
if !output.is_empty() {
|
if !output.label.is_empty() {
|
||||||
|
let auto_text_color = config.auto_select_text.filter(|_| output.selected);
|
||||||
|
|
||||||
let mut layout_job = LayoutJob::simple(
|
let mut layout_job = LayoutJob::simple(
|
||||||
match self.label_prefix {
|
match self.label_prefix {
|
||||||
LabelPrefix::Icon | LabelPrefix::IconAndText => {
|
LabelPrefix::Icon | LabelPrefix::IconAndText => {
|
||||||
@@ -85,23 +103,25 @@ impl BarWidget for Memory {
|
|||||||
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
||||||
},
|
},
|
||||||
config.icon_font_id.clone(),
|
config.icon_font_id.clone(),
|
||||||
ctx.style().visuals.selection.stroke.color,
|
auto_text_color.unwrap_or(ctx.style().visuals.selection.stroke.color),
|
||||||
100.0,
|
100.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
layout_job.append(
|
layout_job.append(
|
||||||
&output,
|
&output.label,
|
||||||
10.0,
|
10.0,
|
||||||
TextFormat {
|
TextFormat {
|
||||||
font_id: config.text_font_id.clone(),
|
font_id: config.text_font_id.clone(),
|
||||||
color: ctx.style().visuals.text_color(),
|
color: auto_text_color.unwrap_or(ctx.style().visuals.text_color()),
|
||||||
valign: Align::Center,
|
valign: Align::Center,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let auto_focus_fill = config.auto_select_fill;
|
||||||
|
|
||||||
config.apply_on_widget(false, ui, |ui| {
|
config.apply_on_widget(false, ui, |ui| {
|
||||||
if SelectableFrame::new(false)
|
if SelectableFrame::new_auto(output.selected, auto_focus_fill)
|
||||||
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
|
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
use crate::bar::Alignment;
|
||||||
use crate::config::LabelPrefix;
|
use crate::config::LabelPrefix;
|
||||||
use crate::render::RenderConfig;
|
use crate::render::RenderConfig;
|
||||||
use crate::selected_frame::SelectableFrame;
|
use crate::selected_frame::SelectableFrame;
|
||||||
use crate::widgets::widget::BarWidget;
|
use crate::widgets::widget::BarWidget;
|
||||||
use eframe::egui::text::LayoutJob;
|
use eframe::egui::text::LayoutJob;
|
||||||
use eframe::egui::Align;
|
use eframe::egui::Align;
|
||||||
|
use eframe::egui::Color32;
|
||||||
use eframe::egui::Context;
|
use eframe::egui::Context;
|
||||||
use eframe::egui::Label;
|
use eframe::egui::Label;
|
||||||
use eframe::egui::TextFormat;
|
use eframe::egui::TextFormat;
|
||||||
@@ -22,18 +24,36 @@ use sysinfo::Networks;
|
|||||||
pub struct NetworkConfig {
|
pub struct NetworkConfig {
|
||||||
/// Enable the Network widget
|
/// Enable the Network widget
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
/// Show total data transmitted
|
/// Show total received and transmitted activity
|
||||||
pub show_total_data_transmitted: bool,
|
#[serde(alias = "show_total_data_transmitted")]
|
||||||
/// Show network activity
|
pub show_total_activity: bool,
|
||||||
pub show_network_activity: bool,
|
/// Show received and transmitted activity
|
||||||
|
#[serde(alias = "show_network_activity")]
|
||||||
|
pub show_activity: bool,
|
||||||
/// Show default interface
|
/// Show default interface
|
||||||
pub show_default_interface: Option<bool>,
|
pub show_default_interface: Option<bool>,
|
||||||
/// Characters to reserve for network activity data
|
/// Characters to reserve for received and transmitted activity
|
||||||
pub network_activity_fill_characters: Option<usize>,
|
#[serde(alias = "network_activity_fill_characters")]
|
||||||
|
pub activity_left_padding: Option<usize>,
|
||||||
/// Data refresh interval (default: 10 seconds)
|
/// Data refresh interval (default: 10 seconds)
|
||||||
pub data_refresh_interval: Option<u64>,
|
pub data_refresh_interval: Option<u64>,
|
||||||
/// Display label prefix
|
/// Display label prefix
|
||||||
pub label_prefix: Option<LabelPrefix>,
|
pub label_prefix: Option<LabelPrefix>,
|
||||||
|
/// Select when the value is over a limit (1MiB is 1048576 bytes (1024*1024))
|
||||||
|
pub auto_select: Option<NetworkSelectConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||||
|
pub struct NetworkSelectConfig {
|
||||||
|
/// Select the total received data when it's over this value
|
||||||
|
pub total_received_over: Option<u64>,
|
||||||
|
/// Select the total transmitted data when it's over this value
|
||||||
|
pub total_transmitted_over: Option<u64>,
|
||||||
|
/// Select the received data when it's over this value
|
||||||
|
pub received_over: Option<u64>,
|
||||||
|
/// Select the transmitted data when it's over this value
|
||||||
|
pub transmitted_over: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NetworkConfig> for Network {
|
impl From<NetworkConfig> for Network {
|
||||||
@@ -42,16 +62,15 @@ impl From<NetworkConfig> for Network {
|
|||||||
|
|
||||||
Self {
|
Self {
|
||||||
enable: value.enable,
|
enable: value.enable,
|
||||||
show_total_activity: value.show_total_data_transmitted,
|
show_total_activity: value.show_total_activity,
|
||||||
show_activity: value.show_network_activity,
|
show_activity: value.show_activity,
|
||||||
show_default_interface: value.show_default_interface.unwrap_or(true),
|
show_default_interface: value.show_default_interface.unwrap_or(true),
|
||||||
networks_network_activity: Networks::new_with_refreshed_list(),
|
networks_network_activity: Networks::new_with_refreshed_list(),
|
||||||
default_interface: String::new(),
|
default_interface: String::new(),
|
||||||
data_refresh_interval,
|
data_refresh_interval,
|
||||||
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon),
|
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon),
|
||||||
network_activity_fill_characters: value
|
auto_select: value.auto_select,
|
||||||
.network_activity_fill_characters
|
activity_left_padding: value.activity_left_padding.unwrap_or_default(),
|
||||||
.unwrap_or_default(),
|
|
||||||
last_state_total_activity: vec![],
|
last_state_total_activity: vec![],
|
||||||
last_state_activity: vec![],
|
last_state_activity: vec![],
|
||||||
last_updated_network_activity: Instant::now()
|
last_updated_network_activity: Instant::now()
|
||||||
@@ -69,11 +88,12 @@ pub struct Network {
|
|||||||
networks_network_activity: Networks,
|
networks_network_activity: Networks,
|
||||||
data_refresh_interval: u64,
|
data_refresh_interval: u64,
|
||||||
label_prefix: LabelPrefix,
|
label_prefix: LabelPrefix,
|
||||||
|
auto_select: Option<NetworkSelectConfig>,
|
||||||
default_interface: String,
|
default_interface: String,
|
||||||
last_state_total_activity: Vec<NetworkReading>,
|
last_state_total_activity: Vec<NetworkReading>,
|
||||||
last_state_activity: Vec<NetworkReading>,
|
last_state_activity: Vec<NetworkReading>,
|
||||||
last_updated_network_activity: Instant,
|
last_updated_network_activity: Instant,
|
||||||
network_activity_fill_characters: usize,
|
activity_left_padding: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Network {
|
impl Network {
|
||||||
@@ -105,24 +125,32 @@ impl Network {
|
|||||||
for (interface_name, data) in &self.networks_network_activity {
|
for (interface_name, data) in &self.networks_network_activity {
|
||||||
if friendly_name.eq(interface_name) {
|
if friendly_name.eq(interface_name) {
|
||||||
if self.show_activity {
|
if self.show_activity {
|
||||||
|
let received = Self::to_pretty_bytes(
|
||||||
|
data.received(),
|
||||||
|
self.data_refresh_interval,
|
||||||
|
);
|
||||||
|
let transmitted = Self::to_pretty_bytes(
|
||||||
|
data.transmitted(),
|
||||||
|
self.data_refresh_interval,
|
||||||
|
);
|
||||||
|
|
||||||
activity.push(NetworkReading::new(
|
activity.push(NetworkReading::new(
|
||||||
NetworkReadingFormat::Speed,
|
NetworkReadingFormat::Speed,
|
||||||
Self::to_pretty_bytes(
|
ReadingValue::from(received),
|
||||||
data.received(),
|
ReadingValue::from(transmitted),
|
||||||
self.data_refresh_interval,
|
|
||||||
),
|
|
||||||
Self::to_pretty_bytes(
|
|
||||||
data.transmitted(),
|
|
||||||
self.data_refresh_interval,
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.show_total_activity {
|
if self.show_total_activity {
|
||||||
|
let total_received =
|
||||||
|
Self::to_pretty_bytes(data.total_received(), 1);
|
||||||
|
let total_transmitted =
|
||||||
|
Self::to_pretty_bytes(data.total_transmitted(), 1);
|
||||||
|
|
||||||
total_activity.push(NetworkReading::new(
|
total_activity.push(NetworkReading::new(
|
||||||
NetworkReadingFormat::Total,
|
NetworkReadingFormat::Total,
|
||||||
Self::to_pretty_bytes(data.total_received(), 1),
|
ReadingValue::from(total_received),
|
||||||
Self::to_pretty_bytes(data.total_transmitted(), 1),
|
ReadingValue::from(total_transmitted),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,105 +166,121 @@ impl Network {
|
|||||||
(activity, total_activity)
|
(activity, total_activity)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reading_to_label(
|
fn reading_to_labels(
|
||||||
&self,
|
&self,
|
||||||
|
select_received: bool,
|
||||||
|
select_transmitted: bool,
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
reading: NetworkReading,
|
reading: &NetworkReading,
|
||||||
config: RenderConfig,
|
config: RenderConfig,
|
||||||
) -> Label {
|
) -> (Label, Label) {
|
||||||
let (text_down, text_up) = match self.label_prefix {
|
let (text_down, text_up) = match self.label_prefix {
|
||||||
LabelPrefix::None | LabelPrefix::Icon => match reading.format {
|
LabelPrefix::None | LabelPrefix::Icon => match reading.format {
|
||||||
NetworkReadingFormat::Speed => (
|
NetworkReadingFormat::Speed => (
|
||||||
format!(
|
format!(
|
||||||
"{: >width$}/s ",
|
"{: >width$}/s ",
|
||||||
reading.received_text,
|
reading.received.pretty,
|
||||||
width = self.network_activity_fill_characters
|
width = self.activity_left_padding
|
||||||
),
|
),
|
||||||
format!(
|
format!(
|
||||||
"{: >width$}/s",
|
"{: >width$}/s",
|
||||||
reading.transmitted_text,
|
reading.transmitted.pretty,
|
||||||
width = self.network_activity_fill_characters
|
width = self.activity_left_padding
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
NetworkReadingFormat::Total => (
|
NetworkReadingFormat::Total => (
|
||||||
format!("{} ", reading.received_text),
|
format!("{} ", reading.received.pretty),
|
||||||
reading.transmitted_text,
|
reading.transmitted.pretty.clone(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
LabelPrefix::Text | LabelPrefix::IconAndText => match reading.format {
|
LabelPrefix::Text | LabelPrefix::IconAndText => match reading.format {
|
||||||
NetworkReadingFormat::Speed => (
|
NetworkReadingFormat::Speed => (
|
||||||
format!(
|
format!(
|
||||||
"DOWN: {: >width$}/s ",
|
"DOWN: {: >width$}/s ",
|
||||||
reading.received_text,
|
reading.received.pretty,
|
||||||
width = self.network_activity_fill_characters
|
width = self.activity_left_padding
|
||||||
),
|
),
|
||||||
format!(
|
format!(
|
||||||
"UP: {: >width$}/s",
|
"UP: {: >width$}/s",
|
||||||
reading.transmitted_text,
|
reading.transmitted.pretty,
|
||||||
width = self.network_activity_fill_characters
|
width = self.activity_left_padding
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
NetworkReadingFormat::Total => (
|
NetworkReadingFormat::Total => (
|
||||||
format!("\u{2211}DOWN: {}/s ", reading.received_text),
|
format!("\u{2211}DOWN: {}/s ", reading.received.pretty),
|
||||||
format!("\u{2211}UP: {}/s", reading.transmitted_text),
|
format!("\u{2211}UP: {}/s", reading.transmitted.pretty),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let icon_format = TextFormat::simple(
|
let auto_text_color_received = config.auto_select_text.filter(|_| select_received);
|
||||||
config.icon_font_id.clone(),
|
let auto_text_color_transmitted = config.auto_select_text.filter(|_| select_transmitted);
|
||||||
ctx.style().visuals.selection.stroke.color,
|
|
||||||
);
|
|
||||||
let text_format = TextFormat {
|
|
||||||
font_id: config.text_font_id.clone(),
|
|
||||||
color: ctx.style().visuals.text_color(),
|
|
||||||
valign: Align::Center,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
// icon
|
// icon
|
||||||
let mut layout_job = LayoutJob::simple(
|
let mut layout_job_down = LayoutJob::simple(
|
||||||
match self.label_prefix {
|
match self.label_prefix {
|
||||||
LabelPrefix::Icon | LabelPrefix::IconAndText => {
|
LabelPrefix::Icon | LabelPrefix::IconAndText => {
|
||||||
egui_phosphor::regular::ARROW_FAT_DOWN.to_string()
|
if select_received {
|
||||||
|
egui_phosphor::regular::ARROW_FAT_LINES_DOWN.to_string()
|
||||||
|
} else {
|
||||||
|
egui_phosphor::regular::ARROW_FAT_DOWN.to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
||||||
},
|
},
|
||||||
icon_format.font_id.clone(),
|
config.icon_font_id.clone(),
|
||||||
icon_format.color,
|
auto_text_color_received.unwrap_or(ctx.style().visuals.selection.stroke.color),
|
||||||
100.0,
|
100.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
// text
|
// text
|
||||||
layout_job.append(
|
layout_job_down.append(
|
||||||
&text_down,
|
&text_down,
|
||||||
ctx.style().spacing.item_spacing.x,
|
ctx.style().spacing.item_spacing.x,
|
||||||
text_format.clone(),
|
TextFormat {
|
||||||
|
font_id: config.text_font_id.clone(),
|
||||||
|
color: auto_text_color_received.unwrap_or(ctx.style().visuals.text_color()),
|
||||||
|
valign: Align::Center,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// icon
|
// icon
|
||||||
layout_job.append(
|
let mut layout_job_up = LayoutJob::simple(
|
||||||
&match self.label_prefix {
|
match self.label_prefix {
|
||||||
LabelPrefix::Icon | LabelPrefix::IconAndText => {
|
LabelPrefix::Icon | LabelPrefix::IconAndText => {
|
||||||
egui_phosphor::regular::ARROW_FAT_UP.to_string()
|
if select_transmitted {
|
||||||
|
egui_phosphor::regular::ARROW_FAT_LINES_UP.to_string()
|
||||||
|
} else {
|
||||||
|
egui_phosphor::regular::ARROW_FAT_UP.to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
||||||
},
|
},
|
||||||
0.0,
|
config.icon_font_id.clone(),
|
||||||
icon_format.clone(),
|
auto_text_color_transmitted.unwrap_or(ctx.style().visuals.selection.stroke.color),
|
||||||
|
100.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
// text
|
// text
|
||||||
layout_job.append(
|
layout_job_up.append(
|
||||||
&text_up,
|
&text_up,
|
||||||
ctx.style().spacing.item_spacing.x,
|
ctx.style().spacing.item_spacing.x,
|
||||||
text_format.clone(),
|
TextFormat {
|
||||||
|
font_id: config.text_font_id.clone(),
|
||||||
|
color: auto_text_color_transmitted.unwrap_or(ctx.style().visuals.text_color()),
|
||||||
|
valign: Align::Center,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
Label::new(layout_job).selectable(false)
|
(
|
||||||
|
Label::new(layout_job_down).selectable(false),
|
||||||
|
Label::new(layout_job_up).selectable(false),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_pretty_bytes(input_in_bytes: u64, timespan_in_s: u64) -> String {
|
fn to_pretty_bytes(input_in_bytes: u64, timespan_in_s: u64) -> (u64, String) {
|
||||||
let input = input_in_bytes as f32 / timespan_in_s as f32;
|
let input = input_in_bytes as f32 / timespan_in_s as f32;
|
||||||
let mut magnitude = input.log(1024f32) as u32;
|
let mut magnitude = input.log(1024f32) as u32;
|
||||||
|
|
||||||
@@ -248,10 +292,30 @@ impl Network {
|
|||||||
let base: Option<DataUnit> = num::FromPrimitive::from_u32(magnitude);
|
let base: Option<DataUnit> = num::FromPrimitive::from_u32(magnitude);
|
||||||
let result = input / ((1u64) << (magnitude * 10)) as f32;
|
let result = input / ((1u64) << (magnitude * 10)) as f32;
|
||||||
|
|
||||||
match base {
|
(
|
||||||
Some(DataUnit::B) => format!("{result:.1} B"),
|
input as u64,
|
||||||
Some(unit) => format!("{result:.1} {unit}iB"),
|
match base {
|
||||||
None => String::from("Unknown data unit"),
|
Some(DataUnit::B) => format!("{result:.1} B"),
|
||||||
|
Some(unit) => format!("{result:.1} {unit}iB"),
|
||||||
|
None => String::from("Unknown data unit"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_frame<R>(
|
||||||
|
&self,
|
||||||
|
selected: bool,
|
||||||
|
auto_focus_fill: Option<Color32>,
|
||||||
|
ui: &mut Ui,
|
||||||
|
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||||
|
) {
|
||||||
|
if SelectableFrame::new_auto(selected, auto_focus_fill)
|
||||||
|
.show(ui, add_contents)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
if let Err(error) = Command::new("cmd.exe").args(["/C", "ncpa"]).spawn() {
|
||||||
|
eprintln!("{}", error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,6 +323,8 @@ impl Network {
|
|||||||
impl BarWidget for Network {
|
impl BarWidget for Network {
|
||||||
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
|
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
|
||||||
if self.enable {
|
if self.enable {
|
||||||
|
let is_reversed = matches!(config.alignment, Some(Alignment::Right));
|
||||||
|
|
||||||
// widget spacing: make sure to use the same config to call the apply_on_widget function
|
// widget spacing: make sure to use the same config to call the apply_on_widget function
|
||||||
let mut render_config = config.clone();
|
let mut render_config = config.clone();
|
||||||
|
|
||||||
@@ -266,17 +332,102 @@ impl BarWidget for Network {
|
|||||||
let (activity, total_activity) = self.network_activity();
|
let (activity, total_activity) = self.network_activity();
|
||||||
|
|
||||||
if self.show_total_activity {
|
if self.show_total_activity {
|
||||||
for reading in total_activity {
|
for reading in &total_activity {
|
||||||
render_config.apply_on_widget(true, ui, |ui| {
|
render_config.apply_on_widget(false, ui, |ui| {
|
||||||
ui.add(self.reading_to_label(ctx, reading, config.clone()));
|
let select_received = self.auto_select.is_some_and(|f| {
|
||||||
|
f.total_received_over
|
||||||
|
.is_some_and(|o| reading.received.value > o)
|
||||||
|
});
|
||||||
|
let select_transmitted = self.auto_select.is_some_and(|f| {
|
||||||
|
f.total_transmitted_over
|
||||||
|
.is_some_and(|o| reading.transmitted.value > o)
|
||||||
|
});
|
||||||
|
|
||||||
|
let labels = self.reading_to_labels(
|
||||||
|
select_received,
|
||||||
|
select_transmitted,
|
||||||
|
ctx,
|
||||||
|
reading,
|
||||||
|
config.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if is_reversed {
|
||||||
|
self.show_frame(
|
||||||
|
select_transmitted,
|
||||||
|
config.auto_select_fill,
|
||||||
|
ui,
|
||||||
|
|ui| ui.add(labels.1),
|
||||||
|
);
|
||||||
|
self.show_frame(
|
||||||
|
select_received,
|
||||||
|
config.auto_select_fill,
|
||||||
|
ui,
|
||||||
|
|ui| ui.add(labels.0),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
self.show_frame(
|
||||||
|
select_received,
|
||||||
|
config.auto_select_fill,
|
||||||
|
ui,
|
||||||
|
|ui| ui.add(labels.0),
|
||||||
|
);
|
||||||
|
self.show_frame(
|
||||||
|
select_transmitted,
|
||||||
|
config.auto_select_fill,
|
||||||
|
ui,
|
||||||
|
|ui| ui.add(labels.1),
|
||||||
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.show_activity {
|
if self.show_activity {
|
||||||
for reading in activity {
|
for reading in &activity {
|
||||||
render_config.apply_on_widget(true, ui, |ui| {
|
render_config.apply_on_widget(false, ui, |ui| {
|
||||||
ui.add(self.reading_to_label(ctx, reading, config.clone()));
|
let select_received = self.auto_select.is_some_and(|f| {
|
||||||
|
f.received_over.is_some_and(|o| reading.received.value > o)
|
||||||
|
});
|
||||||
|
let select_transmitted = self.auto_select.is_some_and(|f| {
|
||||||
|
f.transmitted_over
|
||||||
|
.is_some_and(|o| reading.transmitted.value > o)
|
||||||
|
});
|
||||||
|
|
||||||
|
let labels = self.reading_to_labels(
|
||||||
|
select_received,
|
||||||
|
select_transmitted,
|
||||||
|
ctx,
|
||||||
|
reading,
|
||||||
|
config.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if is_reversed {
|
||||||
|
self.show_frame(
|
||||||
|
select_transmitted,
|
||||||
|
config.auto_select_fill,
|
||||||
|
ui,
|
||||||
|
|ui| ui.add(labels.1),
|
||||||
|
);
|
||||||
|
self.show_frame(
|
||||||
|
select_received,
|
||||||
|
config.auto_select_fill,
|
||||||
|
ui,
|
||||||
|
|ui| ui.add(labels.0),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
self.show_frame(
|
||||||
|
select_received,
|
||||||
|
config.auto_select_fill,
|
||||||
|
ui,
|
||||||
|
|ui| ui.add(labels.0),
|
||||||
|
);
|
||||||
|
self.show_frame(
|
||||||
|
select_transmitted,
|
||||||
|
config.auto_select_fill,
|
||||||
|
ui,
|
||||||
|
|ui| ui.add(labels.1),
|
||||||
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -314,15 +465,9 @@ impl BarWidget for Network {
|
|||||||
);
|
);
|
||||||
|
|
||||||
render_config.apply_on_widget(false, ui, |ui| {
|
render_config.apply_on_widget(false, ui, |ui| {
|
||||||
if SelectableFrame::new(false)
|
self.show_frame(false, None, ui, |ui| {
|
||||||
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
|
ui.add(Label::new(layout_job).selectable(false))
|
||||||
.clicked()
|
});
|
||||||
{
|
|
||||||
if let Err(error) = Command::new("cmd.exe").args(["/C", "ncpa"]).spawn()
|
|
||||||
{
|
|
||||||
eprintln!("{}", error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -339,19 +484,38 @@ enum NetworkReadingFormat {
|
|||||||
Total = 1,
|
Total = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct ReadingValue {
|
||||||
|
value: u64,
|
||||||
|
pretty: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(u64, String)> for ReadingValue {
|
||||||
|
fn from(value: (u64, String)) -> Self {
|
||||||
|
Self {
|
||||||
|
value: value.0,
|
||||||
|
pretty: value.1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct NetworkReading {
|
struct NetworkReading {
|
||||||
pub format: NetworkReadingFormat,
|
format: NetworkReadingFormat,
|
||||||
pub received_text: String,
|
received: ReadingValue,
|
||||||
pub transmitted_text: String,
|
transmitted: ReadingValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetworkReading {
|
impl NetworkReading {
|
||||||
pub fn new(format: NetworkReadingFormat, received: String, transmitted: String) -> Self {
|
fn new(
|
||||||
NetworkReading {
|
format: NetworkReadingFormat,
|
||||||
|
received: ReadingValue,
|
||||||
|
transmitted: ReadingValue,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
format,
|
format,
|
||||||
received_text: received,
|
received,
|
||||||
transmitted_text: transmitted,
|
transmitted,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::bar::Alignment;
|
||||||
use crate::config::LabelPrefix;
|
use crate::config::LabelPrefix;
|
||||||
use crate::render::RenderConfig;
|
use crate::render::RenderConfig;
|
||||||
use crate::selected_frame::SelectableFrame;
|
use crate::selected_frame::SelectableFrame;
|
||||||
@@ -24,6 +25,10 @@ pub struct StorageConfig {
|
|||||||
pub data_refresh_interval: Option<u64>,
|
pub data_refresh_interval: Option<u64>,
|
||||||
/// Display label prefix
|
/// Display label prefix
|
||||||
pub label_prefix: Option<LabelPrefix>,
|
pub label_prefix: Option<LabelPrefix>,
|
||||||
|
/// Select when the current percentage is over this value [[1-100]]
|
||||||
|
pub auto_select_over: Option<u8>,
|
||||||
|
/// Hide when the current percentage is under this value [[1-100]]
|
||||||
|
pub auto_hide_under: Option<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<StorageConfig> for Storage {
|
impl From<StorageConfig> for Storage {
|
||||||
@@ -33,21 +38,30 @@ impl From<StorageConfig> for Storage {
|
|||||||
disks: Disks::new_with_refreshed_list(),
|
disks: Disks::new_with_refreshed_list(),
|
||||||
data_refresh_interval: value.data_refresh_interval.unwrap_or(10),
|
data_refresh_interval: value.data_refresh_interval.unwrap_or(10),
|
||||||
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText),
|
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText),
|
||||||
|
auto_select_over: value.auto_select_over.map(|o| o.clamp(1, 100)),
|
||||||
|
auto_hide_under: value.auto_hide_under.map(|o| o.clamp(1, 100)),
|
||||||
last_updated: Instant::now(),
|
last_updated: Instant::now(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct StorageDisk {
|
||||||
|
label: String,
|
||||||
|
selected: bool,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Storage {
|
pub struct Storage {
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
disks: Disks,
|
disks: Disks,
|
||||||
data_refresh_interval: u64,
|
data_refresh_interval: u64,
|
||||||
label_prefix: LabelPrefix,
|
label_prefix: LabelPrefix,
|
||||||
|
auto_select_over: Option<u8>,
|
||||||
|
auto_hide_under: Option<u8>,
|
||||||
last_updated: Instant,
|
last_updated: Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Storage {
|
impl Storage {
|
||||||
fn output(&mut self) -> Vec<String> {
|
fn output(&mut self) -> Vec<StorageDisk> {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) {
|
if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) {
|
||||||
self.disks.refresh(true);
|
self.disks.refresh(true);
|
||||||
@@ -61,17 +75,26 @@ impl Storage {
|
|||||||
let total = disk.total_space();
|
let total = disk.total_space();
|
||||||
let available = disk.available_space();
|
let available = disk.available_space();
|
||||||
let used = total - available;
|
let used = total - available;
|
||||||
|
let percentage = ((used * 100) / total) as u8;
|
||||||
|
|
||||||
disks.push(match self.label_prefix {
|
let hide = self.auto_hide_under.is_some_and(|u| percentage <= u);
|
||||||
LabelPrefix::Text | LabelPrefix::IconAndText => {
|
|
||||||
format!("{} {}%", mount.to_string_lossy(), (used * 100) / total)
|
if !hide {
|
||||||
}
|
let selected = self.auto_select_over.is_some_and(|o| percentage >= o);
|
||||||
LabelPrefix::None | LabelPrefix::Icon => format!("{}%", (used * 100) / total),
|
|
||||||
})
|
disks.push(StorageDisk {
|
||||||
|
label: match self.label_prefix {
|
||||||
|
LabelPrefix::Text | LabelPrefix::IconAndText => {
|
||||||
|
format!("{} {}%", mount.to_string_lossy(), percentage)
|
||||||
|
}
|
||||||
|
LabelPrefix::None | LabelPrefix::Icon => format!("{}%", percentage),
|
||||||
|
},
|
||||||
|
selected,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
disks.sort();
|
disks.sort_by(|a, b| a.label.cmp(&b.label));
|
||||||
disks.reverse();
|
|
||||||
|
|
||||||
disks
|
disks
|
||||||
}
|
}
|
||||||
@@ -80,7 +103,16 @@ impl Storage {
|
|||||||
impl BarWidget for Storage {
|
impl BarWidget for Storage {
|
||||||
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
|
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
|
||||||
if self.enable {
|
if self.enable {
|
||||||
for output in self.output() {
|
let mut output = self.output();
|
||||||
|
let is_reversed = matches!(config.alignment, Some(Alignment::Right));
|
||||||
|
|
||||||
|
if is_reversed {
|
||||||
|
output.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
for output in output {
|
||||||
|
let auto_text_color = config.auto_select_text.filter(|_| output.selected);
|
||||||
|
|
||||||
let mut layout_job = LayoutJob::simple(
|
let mut layout_job = LayoutJob::simple(
|
||||||
match self.label_prefix {
|
match self.label_prefix {
|
||||||
LabelPrefix::Icon | LabelPrefix::IconAndText => {
|
LabelPrefix::Icon | LabelPrefix::IconAndText => {
|
||||||
@@ -89,23 +121,25 @@ impl BarWidget for Storage {
|
|||||||
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
||||||
},
|
},
|
||||||
config.icon_font_id.clone(),
|
config.icon_font_id.clone(),
|
||||||
ctx.style().visuals.selection.stroke.color,
|
auto_text_color.unwrap_or(ctx.style().visuals.selection.stroke.color),
|
||||||
100.0,
|
100.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
layout_job.append(
|
layout_job.append(
|
||||||
&output,
|
&output.label,
|
||||||
10.0,
|
10.0,
|
||||||
TextFormat {
|
TextFormat {
|
||||||
font_id: config.text_font_id.clone(),
|
font_id: config.text_font_id.clone(),
|
||||||
color: ctx.style().visuals.text_color(),
|
color: auto_text_color.unwrap_or(ctx.style().visuals.text_color()),
|
||||||
valign: Align::Center,
|
valign: Align::Center,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let auto_focus_fill = config.auto_select_fill;
|
||||||
|
|
||||||
config.apply_on_widget(false, ui, |ui| {
|
config.apply_on_widget(false, ui, |ui| {
|
||||||
if SelectableFrame::new(false)
|
if SelectableFrame::new_auto(output.selected, auto_focus_fill)
|
||||||
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
|
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
@@ -113,7 +147,7 @@ impl BarWidget for Storage {
|
|||||||
.args([
|
.args([
|
||||||
"/C",
|
"/C",
|
||||||
"explorer.exe",
|
"explorer.exe",
|
||||||
output.split(' ').collect::<Vec<&str>>()[0],
|
output.label.split(' ').collect::<Vec<&str>>()[0],
|
||||||
])
|
])
|
||||||
.spawn()
|
.spawn()
|
||||||
{
|
{
|
||||||
|
|||||||
404
schema.bar.json
404
schema.bar.json
@@ -26,6 +26,12 @@
|
|||||||
"enable"
|
"enable"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"auto_select_under": {
|
||||||
|
"description": "Select when the current percentage is under this value [[1-100]]",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint8",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
"data_refresh_interval": {
|
"data_refresh_interval": {
|
||||||
"description": "Data refresh interval (default: 10 seconds)",
|
"description": "Data refresh interval (default: 10 seconds)",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@@ -90,6 +96,12 @@
|
|||||||
"enable"
|
"enable"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"auto_select_over": {
|
||||||
|
"description": "Select when the current percentage is over this value [[1-100]]",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint8",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
"data_refresh_interval": {
|
"data_refresh_interval": {
|
||||||
"description": "Data refresh interval (default: 10 seconds)",
|
"description": "Data refresh interval (default: 10 seconds)",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@@ -752,6 +764,12 @@
|
|||||||
"enable"
|
"enable"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"auto_select_over": {
|
||||||
|
"description": "Select when the current percentage is over this value [[1-100]]",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint8",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
"data_refresh_interval": {
|
"data_refresh_interval": {
|
||||||
"description": "Data refresh interval (default: 10 seconds)",
|
"description": "Data refresh interval (default: 10 seconds)",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@@ -810,10 +828,46 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"enable",
|
"enable",
|
||||||
"show_network_activity",
|
"show_activity",
|
||||||
"show_total_data_transmitted"
|
"show_total_activity"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"activity_left_padding": {
|
||||||
|
"description": "Characters to reserve for received and transmitted activity",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"auto_select": {
|
||||||
|
"description": "Select when the value is over a limit (1MiB is 1048576 bytes (1024*1024))",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"received_over": {
|
||||||
|
"description": "Select the received data when it's over this value",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"total_received_over": {
|
||||||
|
"description": "Select the total received data when it's over this value",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"total_transmitted_over": {
|
||||||
|
"description": "Select the total transmitted data when it's over this value",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"transmitted_over": {
|
||||||
|
"description": "Select the transmitted data when it's over this value",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"data_refresh_interval": {
|
"data_refresh_interval": {
|
||||||
"description": "Data refresh interval (default: 10 seconds)",
|
"description": "Data refresh interval (default: 10 seconds)",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@@ -857,22 +911,16 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"network_activity_fill_characters": {
|
"show_activity": {
|
||||||
"description": "Characters to reserve for network activity data",
|
"description": "Show received and transmitted activity",
|
||||||
"type": "integer",
|
"type": "boolean"
|
||||||
"format": "uint",
|
|
||||||
"minimum": 0.0
|
|
||||||
},
|
},
|
||||||
"show_default_interface": {
|
"show_default_interface": {
|
||||||
"description": "Show default interface",
|
"description": "Show default interface",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"show_network_activity": {
|
"show_total_activity": {
|
||||||
"description": "Show network activity",
|
"description": "Show total received and transmitted activity",
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"show_total_data_transmitted": {
|
|
||||||
"description": "Show total data transmitted",
|
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -892,6 +940,18 @@
|
|||||||
"enable"
|
"enable"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"auto_hide_under": {
|
||||||
|
"description": "Hide when the current percentage is under this value [[1-100]]",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint8",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"auto_select_over": {
|
||||||
|
"description": "Select when the current percentage is over this value [[1-100]]",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint8",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
"data_refresh_interval": {
|
"data_refresh_interval": {
|
||||||
"description": "Data refresh interval (default: 10 seconds)",
|
"description": "Data refresh interval (default: 10 seconds)",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@@ -1493,6 +1553,12 @@
|
|||||||
"enable"
|
"enable"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"auto_select_under": {
|
||||||
|
"description": "Select when the current percentage is under this value [[1-100]]",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint8",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
"data_refresh_interval": {
|
"data_refresh_interval": {
|
||||||
"description": "Data refresh interval (default: 10 seconds)",
|
"description": "Data refresh interval (default: 10 seconds)",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@@ -1557,6 +1623,12 @@
|
|||||||
"enable"
|
"enable"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"auto_select_over": {
|
||||||
|
"description": "Select when the current percentage is over this value [[1-100]]",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint8",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
"data_refresh_interval": {
|
"data_refresh_interval": {
|
||||||
"description": "Data refresh interval (default: 10 seconds)",
|
"description": "Data refresh interval (default: 10 seconds)",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@@ -2219,6 +2291,12 @@
|
|||||||
"enable"
|
"enable"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"auto_select_over": {
|
||||||
|
"description": "Select when the current percentage is over this value [[1-100]]",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint8",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
"data_refresh_interval": {
|
"data_refresh_interval": {
|
||||||
"description": "Data refresh interval (default: 10 seconds)",
|
"description": "Data refresh interval (default: 10 seconds)",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@@ -2277,10 +2355,46 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"enable",
|
"enable",
|
||||||
"show_network_activity",
|
"show_activity",
|
||||||
"show_total_data_transmitted"
|
"show_total_activity"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"activity_left_padding": {
|
||||||
|
"description": "Characters to reserve for received and transmitted activity",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"auto_select": {
|
||||||
|
"description": "Select when the value is over a limit (1MiB is 1048576 bytes (1024*1024))",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"received_over": {
|
||||||
|
"description": "Select the received data when it's over this value",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"total_received_over": {
|
||||||
|
"description": "Select the total received data when it's over this value",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"total_transmitted_over": {
|
||||||
|
"description": "Select the total transmitted data when it's over this value",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"transmitted_over": {
|
||||||
|
"description": "Select the transmitted data when it's over this value",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"data_refresh_interval": {
|
"data_refresh_interval": {
|
||||||
"description": "Data refresh interval (default: 10 seconds)",
|
"description": "Data refresh interval (default: 10 seconds)",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@@ -2324,22 +2438,16 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"network_activity_fill_characters": {
|
"show_activity": {
|
||||||
"description": "Characters to reserve for network activity data",
|
"description": "Show received and transmitted activity",
|
||||||
"type": "integer",
|
"type": "boolean"
|
||||||
"format": "uint",
|
|
||||||
"minimum": 0.0
|
|
||||||
},
|
},
|
||||||
"show_default_interface": {
|
"show_default_interface": {
|
||||||
"description": "Show default interface",
|
"description": "Show default interface",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"show_network_activity": {
|
"show_total_activity": {
|
||||||
"description": "Show network activity",
|
"description": "Show total received and transmitted activity",
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"show_total_data_transmitted": {
|
|
||||||
"description": "Show total data transmitted",
|
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2359,6 +2467,18 @@
|
|||||||
"enable"
|
"enable"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"auto_hide_under": {
|
||||||
|
"description": "Hide when the current percentage is under this value [[1-100]]",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint8",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"auto_select_over": {
|
||||||
|
"description": "Select when the current percentage is over this value [[1-100]]",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint8",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
"data_refresh_interval": {
|
"data_refresh_interval": {
|
||||||
"description": "Data refresh interval (default: 10 seconds)",
|
"description": "Data refresh interval (default: 10 seconds)",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@@ -2893,6 +3013,12 @@
|
|||||||
"enable"
|
"enable"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"auto_select_under": {
|
||||||
|
"description": "Select when the current percentage is under this value [[1-100]]",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint8",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
"data_refresh_interval": {
|
"data_refresh_interval": {
|
||||||
"description": "Data refresh interval (default: 10 seconds)",
|
"description": "Data refresh interval (default: 10 seconds)",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@@ -2957,6 +3083,12 @@
|
|||||||
"enable"
|
"enable"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"auto_select_over": {
|
||||||
|
"description": "Select when the current percentage is over this value [[1-100]]",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint8",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
"data_refresh_interval": {
|
"data_refresh_interval": {
|
||||||
"description": "Data refresh interval (default: 10 seconds)",
|
"description": "Data refresh interval (default: 10 seconds)",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@@ -3619,6 +3751,12 @@
|
|||||||
"enable"
|
"enable"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"auto_select_over": {
|
||||||
|
"description": "Select when the current percentage is over this value [[1-100]]",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint8",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
"data_refresh_interval": {
|
"data_refresh_interval": {
|
||||||
"description": "Data refresh interval (default: 10 seconds)",
|
"description": "Data refresh interval (default: 10 seconds)",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@@ -3677,10 +3815,46 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"enable",
|
"enable",
|
||||||
"show_network_activity",
|
"show_activity",
|
||||||
"show_total_data_transmitted"
|
"show_total_activity"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"activity_left_padding": {
|
||||||
|
"description": "Characters to reserve for received and transmitted activity",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"auto_select": {
|
||||||
|
"description": "Select when the value is over a limit (1MiB is 1048576 bytes (1024*1024))",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"received_over": {
|
||||||
|
"description": "Select the received data when it's over this value",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"total_received_over": {
|
||||||
|
"description": "Select the total received data when it's over this value",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"total_transmitted_over": {
|
||||||
|
"description": "Select the total transmitted data when it's over this value",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"transmitted_over": {
|
||||||
|
"description": "Select the transmitted data when it's over this value",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"data_refresh_interval": {
|
"data_refresh_interval": {
|
||||||
"description": "Data refresh interval (default: 10 seconds)",
|
"description": "Data refresh interval (default: 10 seconds)",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@@ -3724,22 +3898,16 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"network_activity_fill_characters": {
|
"show_activity": {
|
||||||
"description": "Characters to reserve for network activity data",
|
"description": "Show received and transmitted activity",
|
||||||
"type": "integer",
|
"type": "boolean"
|
||||||
"format": "uint",
|
|
||||||
"minimum": 0.0
|
|
||||||
},
|
},
|
||||||
"show_default_interface": {
|
"show_default_interface": {
|
||||||
"description": "Show default interface",
|
"description": "Show default interface",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"show_network_activity": {
|
"show_total_activity": {
|
||||||
"description": "Show network activity",
|
"description": "Show total received and transmitted activity",
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"show_total_data_transmitted": {
|
|
||||||
"description": "Show total data transmitted",
|
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3759,6 +3927,18 @@
|
|||||||
"enable"
|
"enable"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"auto_hide_under": {
|
||||||
|
"description": "Hide when the current percentage is under this value [[1-100]]",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint8",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"auto_select_over": {
|
||||||
|
"description": "Select when the current percentage is over this value [[1-100]]",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint8",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
"data_refresh_interval": {
|
"data_refresh_interval": {
|
||||||
"description": "Data refresh interval (default: 10 seconds)",
|
"description": "Data refresh interval (default: 10 seconds)",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@@ -4035,6 +4215,68 @@
|
|||||||
"Crust"
|
"Crust"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"auto_select_fill": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Rosewater",
|
||||||
|
"Flamingo",
|
||||||
|
"Pink",
|
||||||
|
"Mauve",
|
||||||
|
"Red",
|
||||||
|
"Maroon",
|
||||||
|
"Peach",
|
||||||
|
"Yellow",
|
||||||
|
"Green",
|
||||||
|
"Teal",
|
||||||
|
"Sky",
|
||||||
|
"Sapphire",
|
||||||
|
"Blue",
|
||||||
|
"Lavender",
|
||||||
|
"Text",
|
||||||
|
"Subtext1",
|
||||||
|
"Subtext0",
|
||||||
|
"Overlay2",
|
||||||
|
"Overlay1",
|
||||||
|
"Overlay0",
|
||||||
|
"Surface2",
|
||||||
|
"Surface1",
|
||||||
|
"Surface0",
|
||||||
|
"Base",
|
||||||
|
"Mantle",
|
||||||
|
"Crust"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"auto_select_text": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Rosewater",
|
||||||
|
"Flamingo",
|
||||||
|
"Pink",
|
||||||
|
"Mauve",
|
||||||
|
"Red",
|
||||||
|
"Maroon",
|
||||||
|
"Peach",
|
||||||
|
"Yellow",
|
||||||
|
"Green",
|
||||||
|
"Teal",
|
||||||
|
"Sky",
|
||||||
|
"Sapphire",
|
||||||
|
"Blue",
|
||||||
|
"Lavender",
|
||||||
|
"Text",
|
||||||
|
"Subtext1",
|
||||||
|
"Subtext0",
|
||||||
|
"Overlay2",
|
||||||
|
"Overlay1",
|
||||||
|
"Overlay0",
|
||||||
|
"Surface2",
|
||||||
|
"Surface1",
|
||||||
|
"Surface0",
|
||||||
|
"Base",
|
||||||
|
"Mantle",
|
||||||
|
"Crust"
|
||||||
|
]
|
||||||
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"description": "Name of the Catppuccin theme (theme previews: https://github.com/catppuccin/catppuccin)",
|
"description": "Name of the Catppuccin theme (theme previews: https://github.com/catppuccin/catppuccin)",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -4082,6 +4324,48 @@
|
|||||||
"Base0F"
|
"Base0F"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"auto_select_fill": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Base00",
|
||||||
|
"Base01",
|
||||||
|
"Base02",
|
||||||
|
"Base03",
|
||||||
|
"Base04",
|
||||||
|
"Base05",
|
||||||
|
"Base06",
|
||||||
|
"Base07",
|
||||||
|
"Base08",
|
||||||
|
"Base09",
|
||||||
|
"Base0A",
|
||||||
|
"Base0B",
|
||||||
|
"Base0C",
|
||||||
|
"Base0D",
|
||||||
|
"Base0E",
|
||||||
|
"Base0F"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"auto_select_text": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Base00",
|
||||||
|
"Base01",
|
||||||
|
"Base02",
|
||||||
|
"Base03",
|
||||||
|
"Base04",
|
||||||
|
"Base05",
|
||||||
|
"Base06",
|
||||||
|
"Base07",
|
||||||
|
"Base08",
|
||||||
|
"Base09",
|
||||||
|
"Base0A",
|
||||||
|
"Base0B",
|
||||||
|
"Base0C",
|
||||||
|
"Base0D",
|
||||||
|
"Base0E",
|
||||||
|
"Base0F"
|
||||||
|
]
|
||||||
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"description": "Name of the Base16 theme (theme previews: https://tinted-theming.github.io/tinted-gallery/)",
|
"description": "Name of the Base16 theme (theme previews: https://tinted-theming.github.io/tinted-gallery/)",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -4394,6 +4678,48 @@
|
|||||||
"Base0F"
|
"Base0F"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"auto_select_fill": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Base00",
|
||||||
|
"Base01",
|
||||||
|
"Base02",
|
||||||
|
"Base03",
|
||||||
|
"Base04",
|
||||||
|
"Base05",
|
||||||
|
"Base06",
|
||||||
|
"Base07",
|
||||||
|
"Base08",
|
||||||
|
"Base09",
|
||||||
|
"Base0A",
|
||||||
|
"Base0B",
|
||||||
|
"Base0C",
|
||||||
|
"Base0D",
|
||||||
|
"Base0E",
|
||||||
|
"Base0F"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"auto_select_text": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Base00",
|
||||||
|
"Base01",
|
||||||
|
"Base02",
|
||||||
|
"Base03",
|
||||||
|
"Base04",
|
||||||
|
"Base05",
|
||||||
|
"Base06",
|
||||||
|
"Base07",
|
||||||
|
"Base08",
|
||||||
|
"Base09",
|
||||||
|
"Base0A",
|
||||||
|
"Base0B",
|
||||||
|
"Base0C",
|
||||||
|
"Base0D",
|
||||||
|
"Base0E",
|
||||||
|
"Base0F"
|
||||||
|
]
|
||||||
|
},
|
||||||
"colours": {
|
"colours": {
|
||||||
"description": "Colours of the custom Base16 theme palette",
|
"description": "Colours of the custom Base16 theme palette",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|||||||
Reference in New Issue
Block a user