use crate::clients::volume::{self, Event}; use crate::config::CommonConfig; use crate::gtk_helpers::IronbarGtkExt; use crate::modules::{ Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, PopupButton, WidgetContext, }; use crate::{glib_recv, lock, module_impl, send_async, spawn, try_send}; use glib::Propagation; use gtk::pango::EllipsizeMode; use gtk::prelude::*; use gtk::{Button, CellRendererText, ComboBoxText, Label, Orientation, Scale, ToggleButton}; use serde::Deserialize; use std::collections::HashMap; use tokio::sync::mpsc; #[derive(Debug, Clone, Deserialize)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct VolumeModule { /// The format string to use for the widget button label. /// For available tokens, see [below](#formatting-tokens). /// /// **Default**: `{icon} {percentage}%` #[serde(default = "default_format")] format: String, /// Maximum value to allow volume sliders to reach. /// Pulse supports values > 100 but this may result in distortion. /// /// **Default**: `100` #[serde(default = "default_max_volume")] max_volume: f64, /// Volume state icons. /// /// See [icons](#icons). #[serde(default)] icons: Icons, /// See [common options](module-level-options#common-options). #[serde(flatten)] pub common: Option, } fn default_format() -> String { String::from("{icon} {percentage}%") } #[derive(Debug, Clone, Deserialize)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct Icons { /// Icon to show for high volume levels. /// /// **Default**: `󰕾` #[serde(default = "default_icon_volume_high")] volume_high: String, /// Icon to show for medium volume levels. /// /// **Default**: `󰖀` #[serde(default = "default_icon_volume_medium")] volume_medium: String, /// Icon to show for low volume levels. /// /// **Default**: `󰕿` #[serde(default = "default_icon_volume_low")] volume_low: String, /// Icon to show for muted outputs. /// /// **Default**: `󰝟` #[serde(default = "default_icon_muted")] muted: String, } impl Icons { fn volume_icon(&self, volume_percent: f64) -> &str { match volume_percent as u32 { 0..=33 => &self.volume_low, 34..=66 => &self.volume_medium, 67.. => &self.volume_high, } } } impl Default for Icons { fn default() -> Self { Self { volume_high: default_icon_volume_high(), volume_medium: default_icon_volume_medium(), volume_low: default_icon_volume_low(), muted: default_icon_muted(), } } } const fn default_max_volume() -> f64 { 100.0 } fn default_icon_volume_high() -> String { String::from("󰕾") } fn default_icon_volume_medium() -> String { String::from("󰖀") } fn default_icon_volume_low() -> String { String::from("󰕿") } fn default_icon_muted() -> String { String::from("󰝟") } #[derive(Debug, Clone)] pub enum Update { SinkChange(String), SinkVolume(String, f64), SinkMute(String, bool), InputVolume(u32, f64), InputMute(u32, bool), } impl Module