cosmic/widget/icon/
named.rs
1use super::{Handle, Icon};
5use std::{borrow::Cow, path::PathBuf, sync::Arc};
6
7#[derive(Debug, Clone, Default, Hash)]
8pub enum IconFallback {
10 #[default]
11 Default,
13 Names(Vec<Cow<'static, str>>),
15}
16
17#[must_use]
18#[derive(derive_setters::Setters, Clone, Debug, Hash)]
19pub struct Named {
20 pub(super) name: Arc<str>,
22
23 pub fallback: Option<IconFallback>,
25
26 #[setters(strip_option)]
28 pub scale: Option<u16>,
29
30 #[setters(strip_option)]
32 pub size: Option<u16>,
33
34 pub symbolic: bool,
36
37 pub prefer_svg: bool,
39}
40
41impl Named {
42 pub fn new(name: impl Into<Arc<str>>) -> Self {
43 let name = name.into();
44 Self {
45 symbolic: name.ends_with("-symbolic"),
46 name,
47 fallback: Some(IconFallback::Default),
48 size: None,
49 scale: None,
50 prefer_svg: false,
51 }
52 }
53
54 #[cfg(not(windows))]
55 #[must_use]
56 pub fn path(self) -> Option<PathBuf> {
57 let name = &*self.name;
58 let fallback = &self.fallback;
59 let locate = |theme: &str, name| {
60 let mut lookup = freedesktop_icons::lookup(name)
61 .with_theme(theme.as_ref())
62 .with_cache();
63
64 if let Some(scale) = self.scale {
65 lookup = lookup.with_scale(scale);
66 }
67
68 if let Some(size) = self.size {
69 lookup = lookup.with_size(size);
70 }
71
72 if self.prefer_svg {
73 lookup = lookup.force_svg();
74 }
75 lookup.find()
76 };
77
78 let theme = crate::icon_theme::DEFAULT.lock().unwrap();
79 let themes = if theme.as_ref() == crate::icon_theme::COSMIC {
80 vec![theme.as_ref()]
81 } else {
82 vec![theme.as_ref(), crate::icon_theme::COSMIC]
83 };
84
85 let mut result = themes.iter().find_map(|t| locate(t, name));
86
87 if result.is_none() {
89 if matches!(fallback, Some(IconFallback::Default)) {
90 for new_name in name.rmatch_indices('-').map(|(pos, _)| &name[..pos]) {
91 result = themes.iter().find_map(|t| locate(t, new_name));
92 if result.is_some() {
93 break;
94 }
95 }
96 } else if let Some(IconFallback::Names(fallbacks)) = fallback {
97 for fallback in fallbacks {
98 result = themes.iter().find_map(|t| locate(t, fallback));
99 if result.is_some() {
100 break;
101 }
102 }
103 }
104 }
105
106 result
107 }
108
109 #[cfg(windows)]
110 #[must_use]
111 pub fn path(self) -> Option<PathBuf> {
112 None
114 }
115
116 #[inline]
117 pub fn handle(self) -> Handle {
118 Handle {
119 symbolic: self.symbolic,
120 data: super::Data::Name(self),
121 }
122 }
123
124 #[inline]
125 pub fn icon(self) -> Icon {
126 let size = self.size;
127
128 let icon = super::icon(self.handle());
129
130 match size {
131 Some(size) => icon.size(size),
132 None => icon,
133 }
134 }
135}
136
137impl From<Named> for Handle {
138 #[inline]
139 fn from(builder: Named) -> Self {
140 builder.handle()
141 }
142}
143
144impl From<Named> for Icon {
145 #[inline]
146 fn from(builder: Named) -> Self {
147 builder.icon()
148 }
149}
150
151impl<Message: 'static> From<Named> for crate::Element<'_, Message> {
152 #[inline]
153 fn from(builder: Named) -> Self {
154 builder.icon().into()
155 }
156}