mirror of
https://github.com/Zedfrigg/ironbar.git
synced 2025-08-17 14:51:04 +02:00
Merge pull request #651 from JakeStanger/feat/launcher-truncate
Launcher truncate options & related refactors
This commit is contained in:
commit
abf1c1207d
19 changed files with 230 additions and 146 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -3200,7 +3200,7 @@ dependencies = [
|
||||||
"dbusmenu-gtk3-sys",
|
"dbusmenu-gtk3-sys",
|
||||||
"gtk",
|
"gtk",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.0",
|
"thiserror 2.0.3",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"zbus",
|
"zbus",
|
||||||
|
@ -3230,11 +3230,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "2.0.0"
|
version = "2.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "15291287e9bff1bc6f9ff3409ed9af665bec7a5fc8ac079ea96be07bca0e2668"
|
checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl 2.0.0",
|
"thiserror-impl 2.0.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3250,9 +3250,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "2.0.0"
|
version = "2.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22efd00f33f93fa62848a7cab956c3d38c8d43095efda1decfc2b3a5dc0b8972"
|
checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote 1.0.35",
|
"quote 1.0.35",
|
||||||
|
@ -3681,9 +3681,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.8.0"
|
version = "1.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0"
|
checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
|
@ -13,12 +13,12 @@ Supports plain text and images.
|
||||||
> Type: `clipboard`
|
> Type: `clipboard`
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
|-----------------------|---------------------------------------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-----------------------|------------------------------------------------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `icon` | `string` or [image](images) | `` | Icon to show on the widget button. |
|
| `icon` | `string` or [image](images) | `` | Icon to show on the widget button. |
|
||||||
| `icon_size` | `integer` | `32` | Size to render icon at (image icons only). |
|
| `icon_size` | `integer` | `32` | Size to render icon at (image icons only). |
|
||||||
| `max_items` | `integer` | `10` | Maximum number of items to show in the popup. |
|
| `max_items` | `integer` | `10` | Maximum number of items to show in the popup. |
|
||||||
| `truncate` | `'start'` or `'middle'` or `'end'` or `Map` | `null` | The location of the ellipses and where to truncate text from. Leave null to avoid truncating. Use the long-hand `Map` version if specifying a length. |
|
| `truncate` | `'start'` or `'middle'` or `'end'` or `off` or `Map` | `off` | The location of the ellipses and where to truncate text from. Leave null to avoid truncating. Use the long-hand `Map` version if specifying a length. |
|
||||||
| `truncate.mode` | `'start'` or `'middle'` or `'end'` | `null` | The location of the ellipses and where to truncate text from. Leave null to avoid truncating. |
|
| `truncate.mode` | `'start'` or `'middle'` or `'end'` or `off` | `off` | The location of the ellipses and where to truncate text from. Leave null to avoid truncating. |
|
||||||
| `truncate.length` | `integer` | `null` | The fixed width (in chars) of the widget. Leave blank to let GTK automatically handle. |
|
| `truncate.length` | `integer` | `null` | The fixed width (in chars) of the widget. Leave blank to let GTK automatically handle. |
|
||||||
| `truncate.max_length` | `integer` | `null` | The maximum number of characters before truncating. Leave blank to let GTK automatically handle. |
|
| `truncate.max_length` | `integer` | `null` | The maximum number of characters before truncating. Leave blank to let GTK automatically handle. |
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,12 @@ Displays the title and/or icon of the currently focused window.
|
||||||
> Type: `focused`
|
> Type: `focused`
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
|-----------------------|---------------------------------------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-----------------------|------------------------------------------------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `show_icon` | `boolean` | `true` | Whether to show the app's icon. |
|
| `show_icon` | `boolean` | `true` | Whether to show the app's icon. |
|
||||||
| `show_title` | `boolean` | `true` | Whether to show the app's title. |
|
| `show_title` | `boolean` | `true` | Whether to show the app's title. |
|
||||||
| `icon_size` | `integer` | `32` | Size of icon in pixels. |
|
| `icon_size` | `integer` | `32` | Size of icon in pixels. |
|
||||||
| `truncate` | `'start'` or `'middle'` or `'end'` or `Map` | `null` | The location of the ellipses and where to truncate text from. Leave null to avoid truncating. Use the long-hand `Map` version if specifying a length. |
|
| `truncate` | `'start'` or `'middle'` or `'end'` or `off` or `Map` | `off` | The location of the ellipses and where to truncate text from. Leave null to avoid truncating. Use the long-hand `Map` version if specifying a length. |
|
||||||
| `truncate.mode` | `'start'` or `'middle'` or `'end'` | `null` | The location of the ellipses and where to truncate text from. Leave null to avoid truncating. |
|
| `truncate.mode` | `'start'` or `'middle'` or `'end'` or `off` | `off` | The location of the ellipses and where to truncate text from. Leave null to avoid truncating. |
|
||||||
| `truncate.length` | `integer` | `null` | The fixed width (in chars) of the widget. Leave blank to let GTK automatically handle. |
|
| `truncate.length` | `integer` | `null` | The fixed width (in chars) of the widget. Leave blank to let GTK automatically handle. |
|
||||||
| `truncate.max_length` | `integer` | `null` | The maximum number of characters before truncating. Leave blank to let GTK automatically handle. |
|
| `truncate.max_length` | `integer` | `null` | The maximum number of characters before truncating. Leave blank to let GTK automatically handle. |
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,20 @@ Optionally displays a launchable set of favourites.
|
||||||
> Type: `launcher`
|
> Type: `launcher`
|
||||||
|
|
||||||
| | Type | Default | Description |
|
| | Type | Default | Description |
|
||||||
|--------------|------------|---------|-----------------------------------------------------------------------------------------------------|
|
|-----------------------------|---------------------------------------------|----------|--------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `favorites` | `string[]` | `[]` | List of app IDs (or classes) to always show at the start of the launcher |
|
| `favorites` | `string[]` | `[]` | List of app IDs (or classes) to always show at the start of the launcher |
|
||||||
| `show_names` | `boolean` | `false` | Whether to show app names on the button label. Names will still show on tooltips when set to false. |
|
| `show_names` | `boolean` | `false` | Whether to show app names on the button label. Names will still show on tooltips when set to false. |
|
||||||
| `show_icons` | `boolean` | `true` | Whether to show app icons on the button. |
|
| `show_icons` | `boolean` | `true` | Whether to show app icons on the button. |
|
||||||
| `icon_size` | `integer` | `32` | Size to render icon at (image icons only). |
|
| `icon_size` | `integer` | `32` | Size to render icon at (image icons only). |
|
||||||
| `reversed` | `boolean` | `false` | Whether to reverse the order of favorites/items |
|
| `reversed` | `boolean` | `false` | Whether to reverse the order of favorites/items |
|
||||||
|
| `truncate.mode` | `'start'` or `'middle'` or `'end'` or `off` | `end` | The location of the ellipses and where to truncate text from. Applies to application names when `show_names` is enabled. |
|
||||||
|
| `truncate.length` | `integer` | `null` | The fixed width (in chars) of the widget. Leave blank to let GTK automatically handle. |
|
||||||
|
| `truncate.max_length` | `integer` | `null` | The maximum number of characters before truncating. Leave blank to let GTK automatically handle. |
|
||||||
|
| `truncate_popup.mode` | `'start'` or `'middle'` or `'end'` or `off` | `middle` | The location of the ellipses and where to truncate text from. Applies to window names within a group popup. |
|
||||||
|
| `truncate_popup.length` | `integer` | `null` | The fixed width (in chars) of the widget. Leave blank to let GTK automatically handle. |
|
||||||
|
| `truncate_popup.max_length` | `integer` | `25` | The maximum number of characters before truncating. Leave blank to let GTK automatically handle. |
|
||||||
|
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>JSON</summary>
|
<summary>JSON</summary>
|
||||||
|
|
||||||
|
|
|
@ -12,11 +12,11 @@ in MPRIS mode, the widget will listen to all players and automatically detect/di
|
||||||
> Type: `music`
|
> Type: `music`
|
||||||
|
|
||||||
| | Type | Default | Description |
|
| | Type | Default | Description |
|
||||||
|-----------------------|---------------------------------------------|----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-----------------------|------------------------------------------------------|----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `player_type` | `'mpris'` or `'mpd'` | `mpris` | Whether to connect to MPRIS players or an MPD server. |
|
| `player_type` | `'mpris'` or `'mpd'` | `mpris` | Whether to connect to MPRIS players or an MPD server. |
|
||||||
| `format` | `string` | `{title} / {artist}` | Format string for the widget. More info below. |
|
| `format` | `string` | `{title} / {artist}` | Format string for the widget. More info below. |
|
||||||
| `truncate` | `'start'` or `'middle'` or `'end'` or `Map` | `null` | The location of the ellipses and where to truncate text from. Leave null to avoid truncating. Use the long-hand `Map` version if specifying a length. |
|
| `truncate` | `'start'` or `'middle'` or `'end'` or `off` or `Map` | `off` | The location of the ellipses and where to truncate text from. Leave null to avoid truncating. Use the long-hand `Map` version if specifying a length. |
|
||||||
| `truncate.mode` | `'start'` or `'middle'` or `'end'` | `null` | The location of the ellipses and where to truncate text from. Leave null to avoid truncating. |
|
| `truncate.mode` | `'start'` or `'middle'` or `'end'` or `off` | `off` | The location of the ellipses and where to truncate text from. Leave null to avoid truncating. |
|
||||||
| `truncate.length` | `integer` | `null` | The fixed width (in chars) of the widget. Leave blank to let GTK automatically handle. |
|
| `truncate.length` | `integer` | `null` | The fixed width (in chars) of the widget. Leave blank to let GTK automatically handle. |
|
||||||
| `truncate.max_length` | `integer` | `null` | The maximum number of characters before truncating. Leave blank to let GTK automatically handle. |
|
| `truncate.max_length` | `integer` | `null` | The maximum number of characters before truncating. Leave blank to let GTK automatically handle. |
|
||||||
| `icons.play` | `string` or [image](images) | `` | Icon to show when playing. |
|
| `icons.play` | `string` or [image](images) | `` | Icon to show when playing. |
|
||||||
|
|
|
@ -44,7 +44,7 @@ use std::collections::HashMap;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
|
|
||||||
pub use self::common::{CommonConfig, ModuleOrientation, TransitionType};
|
pub use self::common::{CommonConfig, ModuleOrientation, TransitionType};
|
||||||
pub use self::truncate::TruncateMode;
|
pub use self::truncate::{EllipsizeMode, TruncateMode};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone)]
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
#[serde(tag = "type", rename_all = "snake_case")]
|
#[serde(tag = "type", rename_all = "snake_case")]
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
use gtk::pango::EllipsizeMode as GtkEllipsizeMode;
|
use gtk::pango::EllipsizeMode as GtkEllipsizeMode;
|
||||||
use gtk::prelude::*;
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone, Copy)]
|
#[derive(Debug, Deserialize, Clone, Copy, Default)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
|
||||||
pub enum EllipsizeMode {
|
pub enum EllipsizeMode {
|
||||||
|
None,
|
||||||
Start,
|
Start,
|
||||||
Middle,
|
Middle,
|
||||||
|
#[default]
|
||||||
End,
|
End,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<EllipsizeMode> for GtkEllipsizeMode {
|
impl From<EllipsizeMode> for GtkEllipsizeMode {
|
||||||
fn from(value: EllipsizeMode) -> Self {
|
fn from(value: EllipsizeMode) -> Self {
|
||||||
match value {
|
match value {
|
||||||
|
EllipsizeMode::None => Self::None,
|
||||||
EllipsizeMode::Start => Self::Start,
|
EllipsizeMode::Start => Self::Start,
|
||||||
EllipsizeMode::Middle => Self::Middle,
|
EllipsizeMode::Middle => Self::Middle,
|
||||||
EllipsizeMode::End => Self::End,
|
EllipsizeMode::End => Self::End,
|
||||||
|
@ -27,10 +29,23 @@ impl From<EllipsizeMode> for GtkEllipsizeMode {
|
||||||
///
|
///
|
||||||
/// The option can be configured in one of two modes.
|
/// The option can be configured in one of two modes.
|
||||||
///
|
///
|
||||||
|
/// **Default**: `Auto (end)`
|
||||||
|
///
|
||||||
#[derive(Debug, Deserialize, Clone, Copy)]
|
#[derive(Debug, Deserialize, Clone, Copy)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
|
||||||
pub enum TruncateMode {
|
pub enum TruncateMode {
|
||||||
|
/// Do not truncate content.
|
||||||
|
///
|
||||||
|
/// Setting this option may cause excessively long content to overflow other widgets,
|
||||||
|
/// shifting them off-screen.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```corn
|
||||||
|
/// { truncate = "off" }
|
||||||
|
Off,
|
||||||
|
|
||||||
/// Auto mode lets GTK decide when to ellipsize.
|
/// Auto mode lets GTK decide when to ellipsize.
|
||||||
///
|
///
|
||||||
/// To use this mode, set the truncate option to a string
|
/// To use this mode, set the truncate option to a string
|
||||||
|
@ -44,7 +59,7 @@ pub enum TruncateMode {
|
||||||
///
|
///
|
||||||
/// **Valid options**: `start`, `middle`, `end`
|
/// **Valid options**: `start`, `middle`, `end`
|
||||||
/// <br>
|
/// <br>
|
||||||
/// **Default**: `null`
|
/// **Default**: `end`
|
||||||
Auto(EllipsizeMode),
|
Auto(EllipsizeMode),
|
||||||
|
|
||||||
/// Length mode defines a fixed point at which to ellipsize.
|
/// Length mode defines a fixed point at which to ellipsize.
|
||||||
|
@ -88,36 +103,34 @@ pub enum TruncateMode {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TruncateMode {
|
impl Default for TruncateMode {
|
||||||
const fn mode(&self) -> EllipsizeMode {
|
fn default() -> Self {
|
||||||
match self {
|
Self::Auto(EllipsizeMode::default())
|
||||||
Self::Length { mode, .. } | Self::Auto(mode) => *mode,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn length(&self) -> Option<i32> {
|
impl TruncateMode {
|
||||||
|
pub const fn length(&self) -> Option<i32> {
|
||||||
match self {
|
match self {
|
||||||
Self::Auto(_) => None,
|
Self::Auto(_) | Self::Off => None,
|
||||||
Self::Length { length, .. } => *length,
|
Self::Length { length, .. } => *length,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn max_length(&self) -> Option<i32> {
|
pub const fn max_length(&self) -> Option<i32> {
|
||||||
match self {
|
match self {
|
||||||
Self::Auto(_) => None,
|
Self::Auto(_) | Self::Off => None,
|
||||||
Self::Length { max_length, .. } => *max_length,
|
Self::Length { max_length, .. } => *max_length,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn truncate_label(&self, label: >k::Label) {
|
|
||||||
label.set_ellipsize(self.mode().into());
|
|
||||||
|
|
||||||
if let Some(length) = self.length() {
|
|
||||||
label.set_width_chars(length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(length) = self.max_length() {
|
impl From<TruncateMode> for GtkEllipsizeMode {
|
||||||
label.set_max_width_chars(length);
|
fn from(value: TruncateMode) -> Self {
|
||||||
}
|
let mode = match value {
|
||||||
|
TruncateMode::Off => EllipsizeMode::None,
|
||||||
|
TruncateMode::Length { mode, .. } | TruncateMode::Auto(mode) => mode,
|
||||||
|
};
|
||||||
|
mode.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
use crate::config::TruncateMode;
|
||||||
use glib::{markup_escape_text, IsA};
|
use glib::{markup_escape_text, IsA};
|
||||||
|
use gtk::pango::EllipsizeMode;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gtk::{Orientation, Widget};
|
use gtk::{Label, Orientation, Widget};
|
||||||
|
|
||||||
/// Represents a widget's size
|
/// Represents a widget's size
|
||||||
/// and location relative to the bar's start edge.
|
/// and location relative to the bar's start edge.
|
||||||
|
@ -83,9 +85,11 @@ pub trait IronbarLabelExt {
|
||||||
/// the text is escaped to avoid issues with special characters (ie `&`).
|
/// the text is escaped to avoid issues with special characters (ie `&`).
|
||||||
/// Otherwise, the text is used verbatim, and it is up to the user to escape.
|
/// Otherwise, the text is used verbatim, and it is up to the user to escape.
|
||||||
fn set_label_escaped(&self, label: &str);
|
fn set_label_escaped(&self, label: &str);
|
||||||
|
|
||||||
|
fn truncate(&self, mode: TruncateMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IronbarLabelExt for gtk::Label {
|
impl IronbarLabelExt for Label {
|
||||||
fn set_label_escaped(&self, label: &str) {
|
fn set_label_escaped(&self, label: &str) {
|
||||||
if !label.contains("<span") {
|
if !label.contains("<span") {
|
||||||
self.set_label(&markup_escape_text(label));
|
self.set_label(&markup_escape_text(label));
|
||||||
|
@ -93,4 +97,16 @@ impl IronbarLabelExt for gtk::Label {
|
||||||
self.set_label(label);
|
self.set_label(label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn truncate(&self, mode: TruncateMode) {
|
||||||
|
self.set_ellipsize(<TruncateMode as Into<EllipsizeMode>>::into(mode));
|
||||||
|
|
||||||
|
if let Some(length) = mode.length() {
|
||||||
|
self.set_width_chars(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(length) = mode.max_length() {
|
||||||
|
self.set_max_width_chars(length);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ pub fn new_icon_button(input: &str, icon_theme: &IconTheme, size: i32) -> Button
|
||||||
image.add_class("icon");
|
image.add_class("icon");
|
||||||
|
|
||||||
match ImageProvider::parse(input, icon_theme, false, size)
|
match ImageProvider::parse(input, icon_theme, false, size)
|
||||||
.map(|provider| provider.load_into_image(image.clone()))
|
.map(|provider| provider.load_into_image(&image))
|
||||||
{
|
{
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
button.set_image(Some(&image));
|
button.set_image(Some(&image));
|
||||||
|
@ -42,7 +42,7 @@ pub fn new_icon_label(input: &str, icon_theme: &IconTheme, size: i32) -> gtk::Bo
|
||||||
container.add(&image);
|
container.add(&image);
|
||||||
|
|
||||||
ImageProvider::parse(input, icon_theme, false, size)
|
ImageProvider::parse(input, icon_theme, false, size)
|
||||||
.map(|provider| provider.load_into_image(image));
|
.map(|provider| provider.load_into_image(&image));
|
||||||
} else {
|
} else {
|
||||||
let label = Label::builder().use_markup(true).label(input).build();
|
let label = Label::builder().use_markup(true).label(input).build();
|
||||||
label.add_class("icon");
|
label.add_class("icon");
|
||||||
|
|
|
@ -141,7 +141,7 @@ impl<'a> ImageProvider<'a> {
|
||||||
|
|
||||||
/// Attempts to fetch the image from the location
|
/// Attempts to fetch the image from the location
|
||||||
/// and load it into the provided `GTK::Image` widget.
|
/// and load it into the provided `GTK::Image` widget.
|
||||||
pub fn load_into_image(&self, image: gtk::Image) -> Result<()> {
|
pub fn load_into_image(&self, image: >k::Image) -> Result<()> {
|
||||||
// handle remote locations async to avoid blocking UI thread while downloading
|
// handle remote locations async to avoid blocking UI thread while downloading
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
if let ImageLocation::Remote(url) = &self.location {
|
if let ImageLocation::Remote(url) = &self.location {
|
||||||
|
@ -157,6 +157,7 @@ impl<'a> ImageProvider<'a> {
|
||||||
|
|
||||||
{
|
{
|
||||||
let size = self.size;
|
let size = self.size;
|
||||||
|
let image = image.clone();
|
||||||
glib_recv_mpsc!(rx, bytes => {
|
glib_recv_mpsc!(rx, bytes => {
|
||||||
let stream = MemoryInputStream::from_bytes(&bytes);
|
let stream = MemoryInputStream::from_bytes(&bytes);
|
||||||
|
|
||||||
|
@ -181,11 +182,11 @@ impl<'a> ImageProvider<'a> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.load_into_image_sync(&image)?;
|
self.load_into_image_sync(image)?;
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "http"))]
|
#[cfg(not(feature = "http"))]
|
||||||
self.load_into_image_sync(&image)?;
|
self.load_into_image_sync(image)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::clients::clipboard::{self, ClipboardEvent};
|
use crate::clients::clipboard::{self, ClipboardEvent};
|
||||||
use crate::clients::wayland::{ClipboardItem, ClipboardValue};
|
use crate::clients::wayland::{ClipboardItem, ClipboardValue};
|
||||||
use crate::config::{CommonConfig, TruncateMode};
|
use crate::config::{CommonConfig, TruncateMode};
|
||||||
|
use crate::gtk_helpers::IronbarLabelExt;
|
||||||
use crate::image::new_icon_button;
|
use crate::image::new_icon_button;
|
||||||
use crate::modules::{
|
use crate::modules::{
|
||||||
Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, PopupButton, WidgetContext,
|
Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, PopupButton, WidgetContext,
|
||||||
|
@ -195,7 +196,7 @@ impl Module<Button> for ClipboardModule {
|
||||||
button.add(&label);
|
button.add(&label);
|
||||||
|
|
||||||
if let Some(truncate) = self.truncate {
|
if let Some(truncate) = self.truncate {
|
||||||
truncate.truncate_label(&label);
|
label.truncate(truncate);
|
||||||
}
|
}
|
||||||
|
|
||||||
button.style_context().add_class("text");
|
button.style_context().add_class("text");
|
||||||
|
|
|
@ -52,7 +52,7 @@ impl CustomWidget for ImageWidget {
|
||||||
|
|
||||||
dynamic_string(&self.src, move |src| {
|
dynamic_string(&self.src, move |src| {
|
||||||
ImageProvider::parse(&src, &icon_theme, false, self.size)
|
ImageProvider::parse(&src, &icon_theme, false, self.size)
|
||||||
.map(|image| image.load_into_image(gtk_image.clone()));
|
.map(|image| image.load_into_image(>k_image));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::clients::wayland::{self, ToplevelEvent};
|
use crate::clients::wayland::{self, ToplevelEvent};
|
||||||
use crate::config::{CommonConfig, TruncateMode};
|
use crate::config::{CommonConfig, TruncateMode};
|
||||||
use crate::gtk_helpers::IronbarGtkExt;
|
use crate::gtk_helpers::IronbarGtkExt;
|
||||||
|
use crate::gtk_helpers::IronbarLabelExt;
|
||||||
use crate::image::ImageProvider;
|
use crate::image::ImageProvider;
|
||||||
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
|
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
|
||||||
use crate::{glib_recv, module_impl, send_async, spawn, try_send};
|
use crate::{glib_recv, module_impl, send_async, spawn, try_send};
|
||||||
|
@ -145,7 +146,7 @@ impl Module<gtk::Box> for FocusedModule {
|
||||||
label.add_class("label");
|
label.add_class("label");
|
||||||
|
|
||||||
if let Some(truncate) = self.truncate {
|
if let Some(truncate) = self.truncate {
|
||||||
truncate.truncate_label(&label);
|
label.truncate(truncate);
|
||||||
}
|
}
|
||||||
|
|
||||||
container.add(&label);
|
container.add(&label);
|
||||||
|
@ -156,7 +157,7 @@ impl Module<gtk::Box> for FocusedModule {
|
||||||
if let Some((name, id)) = data {
|
if let Some((name, id)) = data {
|
||||||
if self.show_icon {
|
if self.show_icon {
|
||||||
match ImageProvider::parse(&id, &icon_theme, true, self.icon_size)
|
match ImageProvider::parse(&id, &icon_theme, true, self.icon_size)
|
||||||
.map(|image| image.load_into_image(icon.clone()))
|
.map(|image| image.load_into_image(&icon))
|
||||||
{
|
{
|
||||||
Some(Ok(())) => icon.show(),
|
Some(Ok(())) => icon.show(),
|
||||||
_ => icon.hide(),
|
_ => icon.hide(),
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
use super::open_state::OpenState;
|
use super::open_state::OpenState;
|
||||||
use crate::clients::wayland::ToplevelInfo;
|
use crate::clients::wayland::ToplevelInfo;
|
||||||
use crate::config::BarPosition;
|
use crate::config::{BarPosition, TruncateMode};
|
||||||
use crate::gtk_helpers::IronbarGtkExt;
|
use crate::gtk_helpers::{IronbarGtkExt, IronbarLabelExt};
|
||||||
use crate::image::ImageProvider;
|
use crate::image::ImageProvider;
|
||||||
use crate::modules::launcher::{ItemEvent, LauncherUpdate};
|
use crate::modules::launcher::{ItemEvent, LauncherUpdate};
|
||||||
use crate::modules::ModuleUpdateEvent;
|
use crate::modules::ModuleUpdateEvent;
|
||||||
use crate::{read_lock, try_send};
|
use crate::{read_lock, try_send};
|
||||||
use glib::Propagation;
|
use glib::Propagation;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gtk::{Button, IconTheme};
|
use gtk::{Button, IconTheme, Image, Label, Orientation};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
|
@ -134,7 +135,7 @@ pub struct MenuState {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ItemButton {
|
pub struct ItemButton {
|
||||||
pub button: Button,
|
pub button: ImageTextButton,
|
||||||
pub persistent: bool,
|
pub persistent: bool,
|
||||||
pub show_names: bool,
|
pub show_names: bool,
|
||||||
pub menu_state: Rc<RwLock<MenuState>>,
|
pub menu_state: Rc<RwLock<MenuState>>,
|
||||||
|
@ -145,6 +146,7 @@ pub struct AppearanceOptions {
|
||||||
pub show_names: bool,
|
pub show_names: bool,
|
||||||
pub show_icons: bool,
|
pub show_icons: bool,
|
||||||
pub icon_size: i32,
|
pub icon_size: i32,
|
||||||
|
pub truncate: TruncateMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemButton {
|
impl ItemButton {
|
||||||
|
@ -156,16 +158,14 @@ impl ItemButton {
|
||||||
tx: &Sender<ModuleUpdateEvent<LauncherUpdate>>,
|
tx: &Sender<ModuleUpdateEvent<LauncherUpdate>>,
|
||||||
controller_tx: &Sender<ItemEvent>,
|
controller_tx: &Sender<ItemEvent>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut button = Button::builder();
|
let button = ImageTextButton::new();
|
||||||
|
|
||||||
if appearance.show_names {
|
if appearance.show_names {
|
||||||
button = button.label(&item.name);
|
button.label.set_label(&item.name);
|
||||||
|
button.label.truncate(appearance.truncate);
|
||||||
}
|
}
|
||||||
|
|
||||||
let button = button.build();
|
|
||||||
|
|
||||||
if appearance.show_icons {
|
if appearance.show_icons {
|
||||||
let gtk_image = gtk::Image::new();
|
|
||||||
let input = if item.app_id.is_empty() {
|
let input = if item.app_id.is_empty() {
|
||||||
item.name.clone()
|
item.name.clone()
|
||||||
} else {
|
} else {
|
||||||
|
@ -173,26 +173,24 @@ impl ItemButton {
|
||||||
};
|
};
|
||||||
let image = ImageProvider::parse(&input, icon_theme, true, appearance.icon_size);
|
let image = ImageProvider::parse(&input, icon_theme, true, appearance.icon_size);
|
||||||
if let Some(image) = image {
|
if let Some(image) = image {
|
||||||
button.set_image(Some(>k_image));
|
|
||||||
button.set_always_show_image(true);
|
button.set_always_show_image(true);
|
||||||
|
|
||||||
if let Err(err) = image.load_into_image(gtk_image) {
|
if let Err(err) = image.load_into_image(&button.image) {
|
||||||
error!("{err:?}");
|
error!("{err:?}");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let style_context = button.style_context();
|
button.add_class("item");
|
||||||
style_context.add_class("item");
|
|
||||||
|
|
||||||
if item.favorite {
|
if item.favorite {
|
||||||
style_context.add_class("favorite");
|
button.add_class("favorite");
|
||||||
}
|
}
|
||||||
if item.open_state.is_open() {
|
if item.open_state.is_open() {
|
||||||
style_context.add_class("open");
|
button.add_class("open");
|
||||||
}
|
}
|
||||||
if item.open_state.is_focused() {
|
if item.open_state.is_focused() {
|
||||||
style_context.add_class("focused");
|
button.add_class("focused");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -297,3 +295,39 @@ impl ItemButton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ImageTextButton {
|
||||||
|
pub(crate) button: Button,
|
||||||
|
pub(crate) label: Label,
|
||||||
|
image: Image,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImageTextButton {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
let button = Button::new();
|
||||||
|
let container = gtk::Box::new(Orientation::Horizontal, 0);
|
||||||
|
|
||||||
|
let label = Label::new(None);
|
||||||
|
let image = Image::new();
|
||||||
|
|
||||||
|
button.add(&container);
|
||||||
|
|
||||||
|
container.add(&image);
|
||||||
|
container.add(&label);
|
||||||
|
|
||||||
|
ImageTextButton {
|
||||||
|
button,
|
||||||
|
label,
|
||||||
|
image,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for ImageTextButton {
|
||||||
|
type Target = Button;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.button
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,8 +5,10 @@ use self::item::{AppearanceOptions, Item, ItemButton, Window};
|
||||||
use self::open_state::OpenState;
|
use self::open_state::OpenState;
|
||||||
use super::{Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, WidgetContext};
|
use super::{Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, WidgetContext};
|
||||||
use crate::clients::wayland::{self, ToplevelEvent};
|
use crate::clients::wayland::{self, ToplevelEvent};
|
||||||
use crate::config::CommonConfig;
|
use crate::config::{CommonConfig, EllipsizeMode, TruncateMode};
|
||||||
use crate::desktop_file::find_desktop_file;
|
use crate::desktop_file::find_desktop_file;
|
||||||
|
use crate::gtk_helpers::{IronbarGtkExt, IronbarLabelExt};
|
||||||
|
use crate::modules::launcher::item::ImageTextButton;
|
||||||
use crate::{arc_mut, glib_recv, lock, module_impl, send_async, spawn, try_send, write_lock};
|
use crate::{arc_mut, glib_recv, lock, module_impl, send_async, spawn, try_send, write_lock};
|
||||||
use color_eyre::{Help, Report};
|
use color_eyre::{Help, Report};
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
@ -54,6 +56,21 @@ pub struct LauncherModule {
|
||||||
#[serde(default = "crate::config::default_false")]
|
#[serde(default = "crate::config::default_false")]
|
||||||
reversed: bool,
|
reversed: bool,
|
||||||
|
|
||||||
|
// -- common --
|
||||||
|
/// Truncate application names on the bar if they get too long.
|
||||||
|
/// See [truncate options](module-level-options#truncate-mode).
|
||||||
|
///
|
||||||
|
/// **Default**: `Auto (end)`
|
||||||
|
#[serde(default)]
|
||||||
|
truncate: TruncateMode,
|
||||||
|
|
||||||
|
/// Truncate application names in popups if they get too long.
|
||||||
|
/// See [truncate options](module-level-options#truncate-mode).
|
||||||
|
///
|
||||||
|
/// **Default**: `{ mode = "middle" max_length = 25 }`
|
||||||
|
#[serde(default = "default_truncate_popup")]
|
||||||
|
truncate_popup: TruncateMode,
|
||||||
|
|
||||||
/// See [common options](module-level-options#common-options).
|
/// See [common options](module-level-options#common-options).
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub common: Option<CommonConfig>,
|
pub common: Option<CommonConfig>,
|
||||||
|
@ -63,6 +80,14 @@ const fn default_icon_size() -> i32 {
|
||||||
32
|
32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fn default_truncate_popup() -> TruncateMode {
|
||||||
|
TruncateMode::Length {
|
||||||
|
mode: EllipsizeMode::Middle,
|
||||||
|
length: None,
|
||||||
|
max_length: Some(25),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum LauncherUpdate {
|
pub enum LauncherUpdate {
|
||||||
/// Adds item
|
/// Adds item
|
||||||
|
@ -342,6 +367,7 @@ impl Module<gtk::Box> for LauncherModule {
|
||||||
show_names: self.show_names,
|
show_names: self.show_names,
|
||||||
show_icons: self.show_icons,
|
show_icons: self.show_icons,
|
||||||
icon_size: self.icon_size,
|
icon_size: self.icon_size,
|
||||||
|
truncate: self.truncate,
|
||||||
};
|
};
|
||||||
|
|
||||||
let show_names = self.show_names;
|
let show_names = self.show_names;
|
||||||
|
@ -370,9 +396,9 @@ impl Module<gtk::Box> for LauncherModule {
|
||||||
);
|
);
|
||||||
|
|
||||||
if self.reversed {
|
if self.reversed {
|
||||||
container.pack_end(&button.button, false, false, 0);
|
container.pack_end(&button.button.button, false, false, 0);
|
||||||
} else {
|
} else {
|
||||||
container.add(&button.button);
|
container.add(&button.button.button);
|
||||||
}
|
}
|
||||||
|
|
||||||
buttons.insert(item.app_id, button);
|
buttons.insert(item.app_id, button);
|
||||||
|
@ -393,10 +419,10 @@ impl Module<gtk::Box> for LauncherModule {
|
||||||
if button.persistent {
|
if button.persistent {
|
||||||
button.set_open(false);
|
button.set_open(false);
|
||||||
if button.show_names {
|
if button.show_names {
|
||||||
button.button.set_label(&app_id);
|
button.button.label.set_label(&app_id);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
container.remove(&button.button);
|
container.remove(&button.button.button);
|
||||||
buttons.shift_remove(&app_id);
|
buttons.shift_remove(&app_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -423,7 +449,7 @@ impl Module<gtk::Box> for LauncherModule {
|
||||||
|
|
||||||
if show_names {
|
if show_names {
|
||||||
if let Some(button) = buttons.get(&app_id) {
|
if let Some(button) = buttons.get(&app_id) {
|
||||||
button.button.set_label(&name);
|
button.button.label.set_label(&name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -459,7 +485,7 @@ impl Module<gtk::Box> for LauncherModule {
|
||||||
placeholder.set_width_request(MAX_WIDTH);
|
placeholder.set_width_request(MAX_WIDTH);
|
||||||
container.add(&placeholder);
|
container.add(&placeholder);
|
||||||
|
|
||||||
let mut buttons = IndexMap::<String, IndexMap<usize, Button>>::new();
|
let mut buttons = IndexMap::<String, IndexMap<usize, ImageTextButton>>::new();
|
||||||
|
|
||||||
{
|
{
|
||||||
let container = container.clone();
|
let container = container.clone();
|
||||||
|
@ -473,10 +499,11 @@ impl Module<gtk::Box> for LauncherModule {
|
||||||
.windows
|
.windows
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(_, win)| {
|
.map(|(_, win)| {
|
||||||
let button = Button::builder()
|
// TODO: Currently has a useless image
|
||||||
.label(clamp(&win.name))
|
let button = ImageTextButton::new();
|
||||||
.height_request(40)
|
button.set_height_request(40);
|
||||||
.build();
|
button.label.set_label(&win.name);
|
||||||
|
button.label.truncate(self.truncate_popup);
|
||||||
|
|
||||||
{
|
{
|
||||||
let tx = controller_tx.clone();
|
let tx = controller_tx.clone();
|
||||||
|
@ -498,10 +525,11 @@ impl Module<gtk::Box> for LauncherModule {
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(buttons) = buttons.get_mut(&app_id) {
|
if let Some(buttons) = buttons.get_mut(&app_id) {
|
||||||
let button = Button::builder()
|
// TODO: Currently has a useless image
|
||||||
.height_request(40)
|
let button = ImageTextButton::new();
|
||||||
.label(clamp(&win.name))
|
button.set_height_request(40);
|
||||||
.build();
|
button.label.set_label(&win.name);
|
||||||
|
button.label.truncate(self.truncate_popup);
|
||||||
|
|
||||||
{
|
{
|
||||||
let tx = controller_tx.clone();
|
let tx = controller_tx.clone();
|
||||||
|
@ -527,7 +555,7 @@ impl Module<gtk::Box> for LauncherModule {
|
||||||
|
|
||||||
if let Some(buttons) = buttons.get_mut(&app_id) {
|
if let Some(buttons) = buttons.get_mut(&app_id) {
|
||||||
if let Some(button) = buttons.get(&win_id) {
|
if let Some(button) = buttons.get(&win_id) {
|
||||||
button.set_label(&title);
|
button.label.set_label(&title);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -540,8 +568,8 @@ impl Module<gtk::Box> for LauncherModule {
|
||||||
// add app's buttons
|
// add app's buttons
|
||||||
if let Some(buttons) = buttons.get(&app_id) {
|
if let Some(buttons) = buttons.get(&app_id) {
|
||||||
for (_, button) in buttons {
|
for (_, button) in buttons {
|
||||||
button.style_context().add_class("popup-item");
|
button.add_class("popup-item");
|
||||||
container.add(button);
|
container.add(&button.button);
|
||||||
}
|
}
|
||||||
|
|
||||||
container.show_all();
|
container.show_all();
|
||||||
|
@ -556,21 +584,3 @@ impl Module<gtk::Box> for LauncherModule {
|
||||||
Some(container)
|
Some(container)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clamps a string at 24 characters.
|
|
||||||
///
|
|
||||||
/// This is a hacky number derived from
|
|
||||||
/// "what fits inside the 250px popup"
|
|
||||||
/// and probably won't hold up with wide fonts.
|
|
||||||
///
|
|
||||||
/// TODO: Migrate this to truncate system
|
|
||||||
///
|
|
||||||
fn clamp(str: &str) -> String {
|
|
||||||
const MAX_CHARS: usize = 24;
|
|
||||||
|
|
||||||
if str.len() > MAX_CHARS {
|
|
||||||
str.chars().take(MAX_CHARS - 3).collect::<String>() + "..."
|
|
||||||
} else {
|
|
||||||
str.to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -196,7 +196,7 @@ impl Module<Button> for MusicModule {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
if let Some(truncate) = self.truncate {
|
if let Some(truncate) = self.truncate {
|
||||||
truncate.truncate_label(&label);
|
label.truncate(truncate);
|
||||||
}
|
}
|
||||||
|
|
||||||
button_contents.add(&icon_pause);
|
button_contents.add(&icon_pause);
|
||||||
|
@ -415,7 +415,7 @@ impl Module<Button> for MusicModule {
|
||||||
ImageProvider::parse(&cover_path, &icon_theme, false, image_size)
|
ImageProvider::parse(&cover_path, &icon_theme, false, image_size)
|
||||||
}) {
|
}) {
|
||||||
album_image.show();
|
album_image.show();
|
||||||
image.load_into_image(album_image.clone())
|
image.load_into_image(&album_image)
|
||||||
} else {
|
} else {
|
||||||
album_image.set_from_pixbuf(None);
|
album_image.set_from_pixbuf(None);
|
||||||
album_image.hide();
|
album_image.hide();
|
||||||
|
|
|
@ -66,7 +66,7 @@ impl Module<GtkBox> for NetworkManagerModule {
|
||||||
|
|
||||||
let initial_icon_name = "content-loading-symbolic";
|
let initial_icon_name = "content-loading-symbolic";
|
||||||
ImageProvider::parse(initial_icon_name, &icon_theme, false, self.icon_size)
|
ImageProvider::parse(initial_icon_name, &icon_theme, false, self.icon_size)
|
||||||
.map(|provider| provider.load_into_image(icon.clone()));
|
.map(|provider| provider.load_into_image(&icon));
|
||||||
|
|
||||||
let widget_receiver = context.subscribe();
|
let widget_receiver = context.subscribe();
|
||||||
glib_recv!(widget_receiver, state => {
|
glib_recv!(widget_receiver, state => {
|
||||||
|
@ -80,7 +80,7 @@ impl Module<GtkBox> for NetworkManagerModule {
|
||||||
ClientState::Unknown => "dialog-question-symbolic",
|
ClientState::Unknown => "dialog-question-symbolic",
|
||||||
};
|
};
|
||||||
ImageProvider::parse(icon_name, &icon_theme, false, self.icon_size)
|
ImageProvider::parse(icon_name, &icon_theme, false, self.icon_size)
|
||||||
.map(|provider| provider.load_into_image(icon.clone()));
|
.map(|provider| provider.load_into_image(&icon));
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(ModuleParts::new(container, None))
|
Ok(ModuleParts::new(container, None))
|
||||||
|
|
|
@ -66,7 +66,7 @@ impl Module<Label> for SwayModeModule {
|
||||||
let label = label.clone();
|
let label = label.clone();
|
||||||
|
|
||||||
if let Some(truncate) = self.truncate {
|
if let Some(truncate) = self.truncate {
|
||||||
truncate.truncate_label(&label);
|
label.truncate(truncate);
|
||||||
}
|
}
|
||||||
|
|
||||||
let on_mode = move |mode: ModeEvent| {
|
let on_mode = move |mode: ModeEvent| {
|
||||||
|
|
|
@ -210,7 +210,7 @@ impl Module<gtk::Button> for UpowerModule {
|
||||||
icon_name.push_str(&properties.icon_name);
|
icon_name.push_str(&properties.icon_name);
|
||||||
|
|
||||||
ImageProvider::parse(&icon_name, &icon_theme, false, self.icon_size)
|
ImageProvider::parse(&icon_name, &icon_theme, false, self.icon_size)
|
||||||
.map(|provider| provider.load_into_image(icon.clone()));
|
.map(|provider| provider.load_into_image(&icon));
|
||||||
|
|
||||||
label.set_label_escaped(&format);
|
label.set_label_escaped(&format);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue