feat: icon default fallbacks
This commit is contained in:
parent
456b2ddcd5
commit
598bfaa611
3 changed files with 67 additions and 30 deletions
|
|
@ -3,7 +3,7 @@ use cosmic::{
|
||||||
cosmic_theme,
|
cosmic_theme,
|
||||||
iced::widget::{checkbox, column, pick_list, progress_bar, radio, slider, text, text_input},
|
iced::widget::{checkbox, column, pick_list, progress_bar, radio, slider, text, text_input},
|
||||||
iced::{id, Alignment, Length},
|
iced::{id, Alignment, Length},
|
||||||
theme::{self, Button as ButtonTheme, Theme, ThemeType},
|
theme::{self, Button as ButtonTheme, ThemeType},
|
||||||
widget::{
|
widget::{
|
||||||
button, container, icon, segmented_button, segmented_selection, settings, spin_button,
|
button, container, icon, segmented_button, segmented_selection, settings, spin_button,
|
||||||
toggler, view_switcher,
|
toggler, view_switcher,
|
||||||
|
|
@ -417,11 +417,19 @@ impl State {
|
||||||
.padding(8)
|
.padding(8)
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.into(),
|
.into(),
|
||||||
container(text("Primary container with some text").size(24))
|
container(column![
|
||||||
.layer(cosmic_theme::Layer::Primary)
|
text(
|
||||||
.padding(8)
|
"Primary container with some text and a couple icons testing default fallbacks"
|
||||||
.width(Length::Fill)
|
)
|
||||||
.into(),
|
.size(24),
|
||||||
|
icon("microphone-sensitivity-high-symbolic-test", 24)
|
||||||
|
.style(cosmic::theme::Svg::SymbolicActive),
|
||||||
|
icon("microphone-sensitivity-high-symbolic-test", 16).default_fallbacks(false)
|
||||||
|
])
|
||||||
|
.layer(cosmic_theme::Layer::Primary)
|
||||||
|
.padding(8)
|
||||||
|
.width(Length::Fill)
|
||||||
|
.into(),
|
||||||
container(text("Secondary container with some text").size(24))
|
container(text("Secondary container with some text").size(24))
|
||||||
.layer(cosmic_theme::Layer::Secondary)
|
.layer(cosmic_theme::Layer::Secondary)
|
||||||
.padding(8)
|
.padding(8)
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ use std::{
|
||||||
borrow::Cow, collections::hash_map::DefaultHasher, ffi::OsStr, hash::Hash, hash::Hasher,
|
borrow::Cow, collections::hash_map::DefaultHasher, ffi::OsStr, hash::Hash, hash::Hasher,
|
||||||
path::Path, path::PathBuf,
|
path::Path, path::PathBuf,
|
||||||
};
|
};
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash)]
|
#[derive(Clone, Debug, Hash)]
|
||||||
pub enum Handle {
|
pub enum Handle {
|
||||||
|
|
@ -30,30 +31,30 @@ pub enum IconSource<'a> {
|
||||||
impl<'a> IconSource<'a> {
|
impl<'a> IconSource<'a> {
|
||||||
/// Loads the icon as either an image or svg [`Handle`].
|
/// Loads the icon as either an image or svg [`Handle`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn load(&self, size: u16, theme: Option<&str>, svg: bool) -> Handle {
|
pub fn load(
|
||||||
let name_path_buffer: Option<PathBuf>;
|
&self,
|
||||||
|
size: u16,
|
||||||
|
theme: Option<&str>,
|
||||||
|
svg: bool,
|
||||||
|
default_fallbacks: bool,
|
||||||
|
) -> Handle {
|
||||||
|
let mut name_path_buffer: Option<PathBuf>;
|
||||||
let icon: Option<&Path> = match self {
|
let icon: Option<&Path> = match self {
|
||||||
IconSource::Handle(handle) => return handle.clone(),
|
IconSource::Handle(handle) => return handle.clone(),
|
||||||
IconSource::Path(ref path) => Some(path),
|
IconSource::Path(ref path) => Some(path),
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
IconSource::Name(ref name) => {
|
IconSource::Name(ref name) => {
|
||||||
let icon = crate::settings::DEFAULT_ICON_THEME.with(|default_theme| {
|
name_path_buffer = None;
|
||||||
let default_theme: &str = &default_theme.borrow();
|
if let Some(path) = load_icon(name, size, theme) {
|
||||||
freedesktop_icons::lookup(name)
|
name_path_buffer = Some(path);
|
||||||
.with_size(size)
|
} else if default_fallbacks {
|
||||||
.with_theme(theme.unwrap_or(default_theme))
|
for name in name.rmatch_indices('-').map(|(pos, _)| &name[..pos]) {
|
||||||
.with_cache()
|
if let Some(path) = load_icon(name, size, theme) {
|
||||||
.find()
|
name_path_buffer = Some(path);
|
||||||
});
|
break;
|
||||||
|
}
|
||||||
name_path_buffer = if icon.is_none() {
|
}
|
||||||
freedesktop_icons::lookup(name)
|
}
|
||||||
.with_size(size)
|
|
||||||
.with_cache()
|
|
||||||
.find()
|
|
||||||
} else {
|
|
||||||
icon
|
|
||||||
};
|
|
||||||
|
|
||||||
name_path_buffer.as_deref()
|
name_path_buffer.as_deref()
|
||||||
}
|
}
|
||||||
|
|
@ -71,7 +72,7 @@ impl<'a> IconSource<'a> {
|
||||||
let handle = if let Some(path) = icon {
|
let handle = if let Some(path) = icon {
|
||||||
svg::Handle::from_path(path)
|
svg::Handle::from_path(path)
|
||||||
} else {
|
} else {
|
||||||
eprintln!("svg icon '{self:?}' size {size} not found");
|
error!("svg icon '{self:?}' size {size} not found");
|
||||||
svg::Handle::from_memory(Vec::new())
|
svg::Handle::from_memory(Vec::new())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -79,7 +80,7 @@ impl<'a> IconSource<'a> {
|
||||||
} else if let Some(icon) = icon {
|
} else if let Some(icon) = icon {
|
||||||
Handle::Image(icon.into())
|
Handle::Image(icon.into())
|
||||||
} else {
|
} else {
|
||||||
eprintln!("icon '{self:?}' size {size} not found");
|
error!("icon '{self:?}' size {size} not found");
|
||||||
Handle::Image(image::Handle::from_memory(Vec::new()))
|
Handle::Image(image::Handle::from_memory(Vec::new()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -189,6 +190,7 @@ pub struct Icon<'a> {
|
||||||
#[setters(strip_option)]
|
#[setters(strip_option)]
|
||||||
height: Option<Length>,
|
height: Option<Length>,
|
||||||
force_svg: bool,
|
force_svg: bool,
|
||||||
|
default_fallbacks: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX Hopefully this will be enough precision
|
// XXX Hopefully this will be enough precision
|
||||||
|
|
@ -230,6 +232,7 @@ pub fn icon<'a>(source: impl Into<IconSource<'a>>, size: u16) -> Icon<'a> {
|
||||||
theme: None,
|
theme: None,
|
||||||
width: None,
|
width: None,
|
||||||
force_svg: false,
|
force_svg: false,
|
||||||
|
default_fallbacks: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -266,7 +269,12 @@ impl<'a> Icon<'a> {
|
||||||
std::mem::swap(&mut source, &mut self.source);
|
std::mem::swap(&mut source, &mut self.source);
|
||||||
|
|
||||||
iced::widget::lazy(hash, move |_| -> Element<Message> {
|
iced::widget::lazy(hash, move |_| -> Element<Message> {
|
||||||
match source.load(self.size, self.theme.as_deref(), self.force_svg) {
|
match source.load(
|
||||||
|
self.size,
|
||||||
|
self.theme.as_deref(),
|
||||||
|
self.force_svg,
|
||||||
|
self.default_fallbacks,
|
||||||
|
) {
|
||||||
Handle::Svg(handle) => self.svg_element(handle),
|
Handle::Svg(handle) => self.svg_element(handle),
|
||||||
Handle::Image(handle) => self.raster_element(handle),
|
Handle::Image(handle) => self.raster_element(handle),
|
||||||
}
|
}
|
||||||
|
|
@ -280,3 +288,24 @@ impl<'a, Message: 'static> From<Icon<'a>> for Element<'a, Message> {
|
||||||
icon.into_element::<Message>()
|
icon.into_element::<Message>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn load_icon(name: &str, size: u16, theme: Option<&str>) -> Option<PathBuf> {
|
||||||
|
let icon = crate::settings::DEFAULT_ICON_THEME.with(|default_theme| {
|
||||||
|
let default_theme = default_theme.borrow();
|
||||||
|
freedesktop_icons::lookup(name)
|
||||||
|
.with_size(size)
|
||||||
|
.with_theme(theme.unwrap_or(&default_theme))
|
||||||
|
.with_cache()
|
||||||
|
.find()
|
||||||
|
});
|
||||||
|
|
||||||
|
if icon.is_none() {
|
||||||
|
freedesktop_icons::lookup(name)
|
||||||
|
.with_size(size)
|
||||||
|
.with_cache()
|
||||||
|
.find()
|
||||||
|
} else {
|
||||||
|
icon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -542,7 +542,7 @@ where
|
||||||
bounds.x += offset;
|
bounds.x += offset;
|
||||||
bounds.width -= offset;
|
bounds.width -= offset;
|
||||||
|
|
||||||
match icon.load(self.icon_size, None, false) {
|
match icon.load(self.icon_size, None, false, true) {
|
||||||
icon::Handle::Image(_handle) => {
|
icon::Handle::Image(_handle) => {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
@ -583,7 +583,7 @@ where
|
||||||
let width = f32::from(self.icon_size);
|
let width = f32::from(self.icon_size);
|
||||||
let icon_bounds = close_bounds(original_bounds, width, self.button_padding);
|
let icon_bounds = close_bounds(original_bounds, width, self.button_padding);
|
||||||
|
|
||||||
match self.close_icon.load(self.icon_size, None, false) {
|
match self.close_icon.load(self.icon_size, None, false, true) {
|
||||||
icon::Handle::Image(_handle) => {
|
icon::Handle::Image(_handle) => {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue