From 393800aaa2093b9257c43fde8bdb8399f26ebc74 Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Sun, 29 Jan 2023 17:47:01 +0000 Subject: [PATCH] feat(custom): image widget --- docs/modules/Custom.md | 33 ++++++++++++++++++++++++--------- src/image.rs | 2 +- src/modules/custom.rs | 33 ++++++++++++++++++++++++++++++++- src/modules/music/mod.rs | 10 +++++++--- 4 files changed, 64 insertions(+), 14 deletions(-) diff --git a/docs/modules/Custom.md b/docs/modules/Custom.md index 9b1b28d..ac55900 100644 --- a/docs/modules/Custom.md +++ b/docs/modules/Custom.md @@ -18,15 +18,17 @@ It is well worth looking at the examples. ### `Widget` -| Name | Type | Default | Description | -|---------------|------------------------------|--------------|---------------------------------------------------------------------------| -| `widget_type` | `box` or `label` or `button` | `null` | Type of GTK widget to create. | -| `name` | `string` | `null` | Widget name. | -| `class` | `string` | `null` | Widget class name. | -| `label` | `string` | `null` | [`label` and `button`] Widget text label. Pango markup supported. | -| `on_click` | `string` | `null` | [`button`] Command to execute. More on this [below](#commands). | -| `orientation` | `horizontal` or `vertical` | `horizontal` | [`box`] Whether child widgets should be horizontally or vertically added. | -| `widgets` | `Widget[]` | `[]` | [`box`] List of widgets to add to this box. | +| Name | Type | Default | Description | +|---------------|-----------------------------------------|--------------|---------------------------------------------------------------------------| +| `widget_type` | `box` or `label` or `button` or `image` | `null` | Type of GTK widget to create. | +| `name` | `string` | `null` | Widget name. | +| `class` | `string` | `null` | Widget class name. | +| `label` | `string` | `null` | [`label` and `button`] Widget text label. Pango markup supported. | +| `on_click` | `string` | `null` | [`button`] Command to execute. More on this [below](#commands). | +| `src` | `string` | `null` | [`image`] Image source. More on this [below](#images). | +| `size` | `integer` | `null` | [`image`] Width/height of the image. Aspect ratio is preserved. | +| `orientation` | `horizontal` or `vertical` | `horizontal` | [`box`] Whether child widgets should be horizontally or vertically added. | +| `widgets` | `Widget[]` | `[]` | [`box`] List of widgets to add to this box. | ### Labels @@ -56,6 +58,19 @@ The following bar commands are supported: - `popup:open` - `popup:close` +### Images + +Ironbar is capable of loading images from multiple sources: + +- GTK icons: `icon:firefox` +- Local files: `file:///path/to/file.jpg` +- Remote files (over HTTP/HTTPS): `https://example.com/image.jpg` + +Remote images are loaded asynchronously to avoid blocking the UI thread. +Be aware this can cause elements to change size upon load if the image is large enough. + +--- + XML is arguably better-suited and easier to read for this sort of markup, but currently is not supported. Nonetheless, it may be worth comparing the examples to the below equivalent diff --git a/src/image.rs b/src/image.rs index 31202c9..31d5440 100644 --- a/src/image.rs +++ b/src/image.rs @@ -68,7 +68,7 @@ impl<'a> ImageProvider<'a> { None if PathBuf::from(input_name).exists() => { Ok(ImageLocation::Local(PathBuf::from(input_name))) } - None => match get_desktop_icon_name(&input_name) { + None => match get_desktop_icon_name(input_name) { Some(input) => Self::get_location(input, theme, size), None => Err(Report::msg("Unknown image type")), }, diff --git a/src/modules/custom.rs b/src/modules/custom.rs index 1e931b0..f352dbc 100644 --- a/src/modules/custom.rs +++ b/src/modules/custom.rs @@ -1,12 +1,13 @@ use crate::config::CommonConfig; use crate::dynamic_string::DynamicString; +use crate::image::ImageProvider; use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext}; use crate::popup::{ButtonGeometry, Popup}; use crate::script::Script; use crate::{send_async, try_send}; use color_eyre::{Report, Result}; use gtk::prelude::*; -use gtk::{Button, Label, Orientation}; +use gtk::{Button, IconTheme, Label, Orientation}; use serde::Deserialize; use tokio::spawn; use tokio::sync::mpsc::{Receiver, Sender}; @@ -46,6 +47,8 @@ pub struct Widget { class: Option, on_click: Option, orientation: Option, + src: Option, + size: Option, } /// Supported GTK widget types @@ -55,6 +58,7 @@ pub enum WidgetType { Box, Label, Button, + Image, } impl Widget { @@ -64,6 +68,7 @@ impl Widget { WidgetType::Box => parent.add(&self.into_box(&tx, bar_orientation)), WidgetType::Label => parent.add(&self.into_label()), WidgetType::Button => parent.add(&self.into_button(tx, bar_orientation)), + WidgetType::Image => parent.add(&self.into_image()), } } @@ -157,6 +162,32 @@ impl Widget { button } + + fn into_image(self) -> gtk::Image { + let mut builder = gtk::Image::builder(); + + if let Some(name) = self.name { + builder = builder.name(&name); + } + + let gtk_image = builder.build(); + + if let Some(src) = self.src { + let theme = IconTheme::new(); + let size = self.size.unwrap_or(32); + if let Err(err) = ImageProvider::parse(src, &theme, size) + .and_then(|image| image.load_into_image(gtk_image.clone())) + { + error!("{err:?}"); + } + } + + if let Some(class) = self.class { + gtk_image.style_context().add_class(&class); + } + + gtk_image + } } #[derive(Debug)] diff --git a/src/modules/music/mod.rs b/src/modules/music/mod.rs index 1bb4a25..686552f 100644 --- a/src/modules/music/mod.rs +++ b/src/modules/music/mod.rs @@ -1,6 +1,5 @@ mod config; -use std::path::PathBuf; use crate::clients::music::{self, MusicClient, PlayerState, PlayerUpdate, Status, Track}; use crate::image::ImageProvider; use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext}; @@ -11,6 +10,7 @@ use glib::Continue; use gtk::prelude::*; use gtk::{Button, IconTheme, Label, Orientation, Scale}; use regex::Regex; +use std::path::PathBuf; use std::sync::Arc; use std::time::Duration; use tokio::spawn; @@ -306,14 +306,18 @@ impl Module