From 197d5a1c1461d5dc17fea5c7d19a475ed106d3fa Mon Sep 17 00:00:00 2001 From: Michael Aaron Murphy Date: Fri, 6 Jan 2023 01:37:50 +0100 Subject: [PATCH] feat: Add IconSource::load method to get icon handles --- src/widget/icon.rs | 145 ++++++++++++++++++++++++++------------------- 1 file changed, 85 insertions(+), 60 deletions(-) diff --git a/src/widget/icon.rs b/src/widget/icon.rs index 22f8061..f670986 100644 --- a/src/widget/icon.rs +++ b/src/widget/icon.rs @@ -6,7 +6,7 @@ use crate::{Element, Renderer}; use derive_setters::Setters; use iced::{ - widget::{svg, Image}, + widget::{image, svg, Image}, ContentFit, Length, }; use std::{ @@ -14,6 +14,11 @@ use std::{ path::Path, path::PathBuf, }; +pub enum Handle { + Image(image::Handle), + Svg(svg::Handle), +} + #[derive(Debug, Hash)] pub enum IconSource<'a> { Path(Cow<'a, Path>), @@ -21,6 +26,60 @@ pub enum IconSource<'a> { Embedded(Image), } +impl<'a> IconSource<'a> { + /// Loads the icon as either an image or svg [`Handle`]. + #[must_use] + pub fn load(&self, size: u16, theme: Option<&str>, svg: bool) -> Handle { + let name_path_buffer: Option; + let icon: Option<&Path> = match self { + IconSource::Path(path) => Some(path), + IconSource::Name(name) => { + let icon = crate::settings::DEFAULT_ICON_THEME.with(|default_theme| { + let default_theme: &str = &default_theme.borrow(); + freedesktop_icons::lookup(name) + .with_size(size) + .with_theme(theme.unwrap_or(default_theme)) + .with_cache() + .find() + }); + + name_path_buffer = if icon.is_none() { + freedesktop_icons::lookup(name) + .with_size(size) + .with_cache() + .find() + } else { + icon + }; + + name_path_buffer.as_deref() + } + IconSource::Embedded(_) => unimplemented!(), + }; + + let is_svg = svg + || icon + .as_ref() + .map_or(true, |path| path.extension() == Some(OsStr::new("svg"))); + + if is_svg { + let handle = if let Some(path) = icon { + svg::Handle::from_path(path) + } else { + eprintln!("svg icon '{:?}' size {} not found", self, size); + svg::Handle::from_memory(Vec::new()) + }; + + Handle::Svg(handle) + } else if let Some(icon) = icon { + Handle::Image(icon.into()) + } else { + eprintln!("icon '{:?}' size {} not found", self, size); + Handle::Image(image::Handle::from_memory(Vec::new())) + } + } +} + impl<'a> From> for IconSource<'a> { fn from(value: Cow<'a, Path>) -> Self { Self::Path(value) @@ -67,7 +126,7 @@ impl<'a> From for IconSource<'a> { #[derive(Hash, Setters)] pub struct Icon<'a> { #[setters(skip)] - name: IconSource<'a>, + source: IconSource<'a>, #[setters(strip_option, into)] theme: Option>, style: crate::theme::Svg, @@ -83,11 +142,11 @@ pub struct Icon<'a> { /// A lazily-generated icon. #[must_use] -pub fn icon<'a>(name: impl Into>, size: u16) -> Icon<'a> { +pub fn icon<'a>(source: impl Into>, size: u16) -> Icon<'a> { Icon { content_fit: None, height: None, - name: name.into(), + source: source.into(), size, style: crate::theme::Svg::default(), theme: None, @@ -99,7 +158,7 @@ pub fn icon<'a>(name: impl Into>, size: u16) -> Icon<'a> { impl<'a> Icon<'a> { #[must_use] fn into_element(self) -> Element<'a, Message> { - if let IconSource::Embedded(mut image) = self.name { + if let IconSource::Embedded(mut image) = self.source { image = image .width(self.width.unwrap_or(Length::Units(self.size))) .height(self.height.unwrap_or(Length::Units(self.size))); @@ -119,65 +178,31 @@ impl<'a> Icon<'a> { let hash = hasher.finish(); iced_lazy::lazy(hash, move || -> Element { - let name_path_buffer: Option; - let icon: Option<&Path> = match &self.name { - IconSource::Path(path) => Some(path), - IconSource::Name(name) => { - let icon = crate::settings::DEFAULT_ICON_THEME.with(|default_theme| { - let default_theme: &str = &default_theme.borrow(); - freedesktop_icons::lookup(name) - .with_size(self.size) - .with_theme(self.theme.as_deref().unwrap_or(default_theme)) - .with_cache() - .find() - }); + match self + .source + .load(self.size, self.theme.as_deref(), self.force_svg) + { + Handle::Svg(handle) => { + let mut widget = svg::Svg::::new(handle) + .style(self.style) + .width(self.width.unwrap_or(Length::Units(self.size))) + .height(self.height.unwrap_or(Length::Units(self.size))); - name_path_buffer = if icon.is_none() { - freedesktop_icons::lookup(name) - .with_size(self.size) - .with_cache() - .find() - } else { - icon - }; + if let Some(content_fit) = self.content_fit { + widget = widget.content_fit(content_fit); + } - name_path_buffer.as_deref() + widget.into() } - IconSource::Embedded(_) => unimplemented!(), - }; - - let is_svg = self.force_svg - || icon - .as_ref() - .map_or(true, |path| path.extension() == Some(OsStr::new("svg"))); - - if is_svg { - let handle = if let Some(path) = icon { - svg::Handle::from_path(path) - } else { - eprintln!("icon '{:?}' size {} not found", &self.name, self.size); - svg::Handle::from_memory(Vec::new()) - }; - - let mut widget = svg::Svg::::new(handle) - .style(self.style) - .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 { - widget = widget.content_fit(content_fit); + Handle::Image(handle) => { + let mut image = Image::new(handle) + .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); + } + image.into() } - - widget.into() - } else { - let icon_path = icon.unwrap(); - let mut image = Image::new(icon_path) - .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); - } - image.into() } }) .into()