diff --git a/src/widget/header_bar.rs b/src/widget/header_bar.rs index 1c6b26e6..23885fbd 100644 --- a/src/widget/header_bar.rs +++ b/src/widget/header_bar.rs @@ -95,6 +95,7 @@ impl<'a, Message: Clone + 'static> HeaderBar<'a, Message> { let icon = |name, size, on_press| { super::icon(name, size) + .force_svg(true) .style(crate::theme::Svg::SymbolicActive) .apply(iced::widget::button) .style(theme::Button::Text) diff --git a/src/widget/icon.rs b/src/widget/icon.rs index bccf63cf..6ff4203b 100644 --- a/src/widget/icon.rs +++ b/src/widget/icon.rs @@ -7,17 +7,54 @@ use iced::{ widget::{svg, Image}, Length, ContentFit, }; -use std::{borrow::Cow, ffi::OsStr}; +use std::{borrow::{Cow, Borrow}, ffi::OsStr, path::Path}; use std::hash::Hash; use std::rc::Rc; use derive_setters::Setters; use crate::{Element, Renderer}; +#[derive(Debug, Hash)] +pub enum IconSource<'a> { + Path(&'a Path), + Name(Cow<'a, str>), + Embedded(Image), +} + +impl<'a> From<&'a Path> for IconSource<'a> { + fn from(value: &'a Path) -> Self { + Self::Path(value) + } +} + +impl<'a> From> for IconSource<'a> { + fn from(value: Cow<'a, str>) -> Self { + Self::Name(value) + } +} + +impl<'a> From for IconSource<'a> { + fn from(value: String) -> Self { + Self::Name(value.into()) + } +} + +impl<'a> From<&'a str> for IconSource<'a> { + fn from(value: &'a str) -> Self { + Self::Name(value.into()) + } +} + +impl<'a> From for IconSource<'a> { + fn from(value: Image) -> Self { + Self::Embedded(value) + } +} + /// A lazily-generated icon. #[derive(Hash, Setters)] pub struct Icon<'a> { #[setters(skip)] - name: Cow<'a, str>, + name: IconSource<'a>, #[setters(into)] theme: Cow<'a, str>, style: crate::theme::Svg, @@ -28,11 +65,13 @@ pub struct Icon<'a> { width: Option, #[setters(strip_option)] height: Option, + force_svg: bool, + } /// A lazily-generated icon. #[must_use] -pub fn icon<'a>(name: impl Into>, size: u16) -> Icon<'a> { +pub fn icon<'a>(name: impl Into>, size: u16) -> Icon<'a> { Icon { content_fit: None, height: None, @@ -41,35 +80,54 @@ pub fn icon<'a>(name: impl Into>, size: u16) -> Icon<'a> { style: crate::theme::Svg::default(), theme: Cow::Borrowed("Pop"), width: None, + force_svg: false } } impl<'a> Icon<'a> { #[must_use] fn into_element(self) -> Element<'a, Message> { + if let IconSource::Embedded(mut image) = self.name { + image = image + .width(self.width.unwrap_or(Length::Units(self.size))) + .height(self.height.unwrap_or(Length::Units(self.size))); + if let Some(content_fit) = self.content_fit { + image = image.content_fit(content_fit); + } + return image.into(); + } + let element = Rc::new(self); let element_clone = Rc::clone(&element); iced_lazy::lazy(element_clone, move || -> Element { - let icon = freedesktop_icons::lookup(&element.name) - .with_size(element.size) - .with_theme(&element.theme) - .with_cache() - .find(); - let icon = if icon.is_none() { - freedesktop_icons::lookup(&element.name) - .with_size(element.size) - .with_cache() - .find() - } else { - icon + let icon = match &element.name { + IconSource::Path(path) => Some(Cow::from(*path)), + IconSource::Name(name) => { + let icon = freedesktop_icons::lookup(&name) + .with_size(element.size) + .with_theme(&element.theme) + .with_cache() + .find(); + if icon.is_none() { + freedesktop_icons::lookup(&name) + .with_size(element.size) + .with_cache() + .find() + } else { + icon + }.map(|p| Cow::from(p)) + }, + IconSource::Embedded(_) => unimplemented!(), }; - if icon.as_ref().map(|path| path.extension() == Some(&OsStr::new("svg"))).unwrap_or(true) { + let is_svg = element.force_svg || icon.as_ref().map(|path| path.extension() == Some(&OsStr::new("svg"))).unwrap_or(true); + + if is_svg { let handle = if let Some(path) = icon { svg::Handle::from_path(path) } else { - eprintln!("icon '{}' size {} not found", element.name, element.size); + eprintln!("icon '{:?}' size {} not found", &element.name, element.size); svg::Handle::from_memory(Vec::new()) }; diff --git a/src/widget/nav_button.rs b/src/widget/nav_button.rs index f2711845..d9ae2888 100644 --- a/src/widget/nav_button.rs +++ b/src/widget/nav_button.rs @@ -39,6 +39,7 @@ impl<'a, Message: 'static + Clone> From> for Element<'a, }, 24, ) + .force_svg(true) .style(theme::Svg::SymbolicActive) .width(Length::Units(24)) .height(Length::Fill);