cosmic/widget/icon/
named.rs1use 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 let symbolic = name.ends_with("-symbolic");
45 Self {
46 symbolic,
47 name,
48 fallback: Some(IconFallback::Default),
49 size: None,
50 scale: None,
51 prefer_svg: symbolic,
52 }
53 }
54
55 #[cfg(not(windows))]
56 #[must_use]
57 pub fn path(self) -> Option<PathBuf> {
58 let name = &*self.name;
59 let fallback = &self.fallback;
60 let locate = |theme: &str, name| {
61 let mut lookup = freedesktop_icons::lookup(name)
62 .with_theme(theme.as_ref())
63 .with_cache();
64
65 if let Some(scale) = self.scale {
66 lookup = lookup.with_scale(scale);
67 }
68
69 if let Some(size) = self.size {
70 lookup = lookup.with_size(size);
71 }
72
73 if self.prefer_svg {
74 lookup = lookup.force_svg();
75 }
76 lookup.find()
77 };
78
79 let theme = crate::icon_theme::DEFAULT.lock().unwrap();
80 let themes = if theme.as_ref() == crate::icon_theme::COSMIC {
81 vec![theme.as_ref()]
82 } else {
83 vec![theme.as_ref(), crate::icon_theme::COSMIC]
84 };
85
86 let mut result = themes.iter().find_map(|t| locate(t, name));
87
88 if result.is_none() {
90 if matches!(fallback, Some(IconFallback::Default)) {
91 for new_name in name.rmatch_indices('-').map(|(pos, _)| &name[..pos]) {
92 result = themes.iter().find_map(|t| locate(t, new_name));
93 if result.is_some() {
94 break;
95 }
96 }
97 } else if let Some(IconFallback::Names(fallbacks)) = fallback {
98 for fallback in fallbacks {
99 result = themes.iter().find_map(|t| locate(t, fallback));
100 if result.is_some() {
101 break;
102 }
103 }
104 }
105 }
106
107 result
108 }
109
110 #[cfg(windows)]
111 #[must_use]
112 pub fn path(self) -> Option<PathBuf> {
113 None
115 }
116
117 #[inline]
118 pub fn handle(self) -> Handle {
119 Handle {
120 symbolic: self.symbolic,
121 data: super::Data::Name(self),
122 }
123 }
124
125 #[inline]
126 pub fn icon(self) -> Icon {
127 let size = self.size;
128
129 let icon = super::icon(self.handle());
130
131 match size {
132 Some(size) => icon.size(size),
133 None => icon,
134 }
135 }
136}
137
138impl From<Named> for Handle {
139 #[inline]
140 fn from(builder: Named) -> Self {
141 builder.handle()
142 }
143}
144
145impl From<Named> for Icon {
146 #[inline]
147 fn from(builder: Named) -> Self {
148 builder.icon()
149 }
150}
151
152impl<Message: 'static> From<Named> for crate::Element<'_, Message> {
153 #[inline]
154 fn from(builder: Named) -> Self {
155 builder.icon().into()
156 }
157}