feat: Add IconSource::load method to get icon handles
This commit is contained in:
parent
5224c9b75c
commit
197d5a1c14
1 changed files with 85 additions and 60 deletions
|
|
@ -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<PathBuf>;
|
||||
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<Cow<'a, Path>> for IconSource<'a> {
|
||||
fn from(value: Cow<'a, Path>) -> Self {
|
||||
Self::Path(value)
|
||||
|
|
@ -67,7 +126,7 @@ impl<'a> From<Image> for IconSource<'a> {
|
|||
#[derive(Hash, Setters)]
|
||||
pub struct Icon<'a> {
|
||||
#[setters(skip)]
|
||||
name: IconSource<'a>,
|
||||
source: IconSource<'a>,
|
||||
#[setters(strip_option, into)]
|
||||
theme: Option<Cow<'a, str>>,
|
||||
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<IconSource<'a>>, size: u16) -> Icon<'a> {
|
||||
pub fn icon<'a>(source: impl Into<IconSource<'a>>, 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<IconSource<'a>>, size: u16) -> Icon<'a> {
|
|||
impl<'a> Icon<'a> {
|
||||
#[must_use]
|
||||
fn into_element<Message: 'static>(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<Message> {
|
||||
let name_path_buffer: Option<PathBuf>;
|
||||
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::<Renderer>::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::<Renderer>::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()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue