muda_win/icon.rs
1use crate::platform_impl::PlatformIcon;
2use std::{error::Error, fmt, io, mem};
3
4#[repr(C)]
5#[derive(Debug)]
6pub(crate) struct Pixel {
7 pub(crate) r: u8,
8 pub(crate) g: u8,
9 pub(crate) b: u8,
10 pub(crate) a: u8,
11}
12
13pub(crate) const PIXEL_SIZE: usize = mem::size_of::<Pixel>();
14
15#[derive(Debug)]
16/// An error produced when using [`Icon::from_rgba`] with invalid arguments.
17pub enum BadIcon {
18 /// Produced when the length of the `rgba` argument isn't divisible by 4, thus `rgba` can't be
19 /// safely interpreted as 32bpp RGBA pixels.
20 ByteCountNotDivisibleBy4 { byte_count: usize },
21 /// Produced when the number of pixels (`rgba.len() / 4`) isn't equal to `width * height`.
22 /// At least one of your arguments is incorrect.
23 DimensionsVsPixelCount {
24 width: u32,
25 height: u32,
26 width_x_height: usize,
27 pixel_count: usize,
28 },
29 /// Produced when underlying OS functionality failed to create the icon
30 OsError(io::Error),
31}
32
33impl fmt::Display for BadIcon {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 match self {
36 BadIcon::ByteCountNotDivisibleBy4 { byte_count } => write!(f,
37 "The length of the `rgba` argument ({:?}) isn't divisible by 4, making it impossible to interpret as 32bpp RGBA pixels.",
38 byte_count,
39 ),
40 BadIcon::DimensionsVsPixelCount {
41 width,
42 height,
43 width_x_height,
44 pixel_count,
45 } => write!(f,
46 "The specified dimensions ({:?}x{:?}) don't match the number of pixels supplied by the `rgba` argument ({:?}). For those dimensions, the expected pixel count is {:?}.",
47 width, height, pixel_count, width_x_height,
48 ),
49 BadIcon::OsError(e) => write!(f, "OS error when instantiating the icon: {:?}", e),
50 }
51 }
52}
53
54impl Error for BadIcon {
55 fn source(&self) -> Option<&(dyn Error + 'static)> {
56 Some(self)
57 }
58}
59
60#[derive(Debug, Clone, PartialEq, Eq)]
61pub(crate) struct RgbaIcon {
62 pub(crate) rgba: Vec<u8>,
63 pub(crate) width: u32,
64 pub(crate) height: u32,
65}
66
67/// For platforms which don't have window icons (e.g. web)
68#[derive(Debug, Clone, PartialEq, Eq)]
69pub(crate) struct NoIcon;
70
71#[allow(dead_code)] // These are not used on every platform
72mod constructors {
73 use super::*;
74
75 impl RgbaIcon {
76 pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
77 if rgba.len() % PIXEL_SIZE != 0 {
78 return Err(BadIcon::ByteCountNotDivisibleBy4 {
79 byte_count: rgba.len(),
80 });
81 }
82 let pixel_count = rgba.len() / PIXEL_SIZE;
83 if pixel_count != (width * height) as usize {
84 Err(BadIcon::DimensionsVsPixelCount {
85 width,
86 height,
87 width_x_height: (width * height) as usize,
88 pixel_count,
89 })
90 } else {
91 Ok(RgbaIcon {
92 rgba,
93 width,
94 height,
95 })
96 }
97 }
98 }
99
100 impl NoIcon {
101 pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
102 // Create the rgba icon anyway to validate the input
103 let _ = RgbaIcon::from_rgba(rgba, width, height)?;
104 Ok(NoIcon)
105 }
106 }
107}
108
109/// An icon used for the window titlebar, taskbar, etc.
110#[derive(Clone)]
111pub struct Icon {
112 pub(crate) inner: PlatformIcon,
113}
114
115impl fmt::Debug for Icon {
116 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
117 fmt::Debug::fmt(&self.inner, formatter)
118 }
119}
120
121impl Icon {
122 /// Creates an icon from 32bpp RGBA data.
123 ///
124 /// The length of `rgba` must be divisible by 4, and `width * height` must equal
125 /// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error.
126 pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
127 Ok(Icon {
128 inner: PlatformIcon::from_rgba(rgba, width, height)?,
129 })
130 }
131
132 /// Create an icon from a file path.
133 ///
134 /// Specify `size` to load a specific icon size from the file, or `None` to load the default
135 /// icon size from the file.
136 ///
137 /// In cases where the specified size does not exist in the file, Windows may perform scaling
138 /// to get an icon of the desired size.
139 #[cfg(windows)]
140 pub fn from_path<P: AsRef<std::path::Path>>(
141 path: P,
142 size: Option<(u32, u32)>,
143 ) -> Result<Self, BadIcon> {
144 let win_icon = PlatformIcon::from_path(path, size)?;
145 Ok(Icon { inner: win_icon })
146 }
147
148 /// Create an icon from a resource embedded in this executable or library.
149 ///
150 /// Specify `size` to load a specific icon size from the file, or `None` to load the default
151 /// icon size from the file.
152 ///
153 /// In cases where the specified size does not exist in the file, Windows may perform scaling
154 /// to get an icon of the desired size.
155 #[cfg(windows)]
156 pub fn from_resource(ordinal: u16, size: Option<(u32, u32)>) -> Result<Self, BadIcon> {
157 let win_icon = PlatformIcon::from_resource(ordinal, size)?;
158 Ok(Icon { inner: win_icon })
159 }
160}
161
162/// A native Icon to be used for the menu item
163///
164/// ## Platform-specific:
165///
166/// - **Windows / Linux**: Unsupported.
167#[derive(Debug, Clone, Copy, PartialEq, Eq)]
168#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
169pub enum NativeIcon {
170 /// An add item template image.
171 Add,
172 /// Advanced preferences toolbar icon for the preferences window.
173 Advanced,
174 /// A Bluetooth template image.
175 Bluetooth,
176 /// Bookmarks image suitable for a template.
177 Bookmarks,
178 /// A caution image.
179 Caution,
180 /// A color panel toolbar icon.
181 ColorPanel,
182 /// A column view mode template image.
183 ColumnView,
184 /// A computer icon.
185 Computer,
186 /// An enter full-screen mode template image.
187 EnterFullScreen,
188 /// Permissions for all users.
189 Everyone,
190 /// An exit full-screen mode template image.
191 ExitFullScreen,
192 /// A cover flow view mode template image.
193 FlowView,
194 /// A folder image.
195 Folder,
196 /// A burnable folder icon.
197 FolderBurnable,
198 /// A smart folder icon.
199 FolderSmart,
200 /// A link template image.
201 FollowLinkFreestanding,
202 /// A font panel toolbar icon.
203 FontPanel,
204 /// A `go back` template image.
205 GoLeft,
206 /// A `go forward` template image.
207 GoRight,
208 /// Home image suitable for a template.
209 Home,
210 /// An iChat Theater template image.
211 IChatTheater,
212 /// An icon view mode template image.
213 IconView,
214 /// An information toolbar icon.
215 Info,
216 /// A template image used to denote invalid data.
217 InvalidDataFreestanding,
218 /// A generic left-facing triangle template image.
219 LeftFacingTriangle,
220 /// A list view mode template image.
221 ListView,
222 /// A locked padlock template image.
223 LockLocked,
224 /// An unlocked padlock template image.
225 LockUnlocked,
226 /// A horizontal dash, for use in menus.
227 MenuMixedState,
228 /// A check mark template image, for use in menus.
229 MenuOnState,
230 /// A MobileMe icon.
231 MobileMe,
232 /// A drag image for multiple items.
233 MultipleDocuments,
234 /// A network icon.
235 Network,
236 /// A path button template image.
237 Path,
238 /// General preferences toolbar icon for the preferences window.
239 PreferencesGeneral,
240 /// A Quick Look template image.
241 QuickLook,
242 /// A refresh template image.
243 RefreshFreestanding,
244 /// A refresh template image.
245 Refresh,
246 /// A remove item template image.
247 Remove,
248 /// A reveal contents template image.
249 RevealFreestanding,
250 /// A generic right-facing triangle template image.
251 RightFacingTriangle,
252 /// A share view template image.
253 Share,
254 /// A slideshow template image.
255 Slideshow,
256 /// A badge for a `smart` item.
257 SmartBadge,
258 /// Small green indicator, similar to iChat’s available image.
259 StatusAvailable,
260 /// Small clear indicator.
261 StatusNone,
262 /// Small yellow indicator, similar to iChat’s idle image.
263 StatusPartiallyAvailable,
264 /// Small red indicator, similar to iChat’s unavailable image.
265 StatusUnavailable,
266 /// A stop progress template image.
267 StopProgressFreestanding,
268 /// A stop progress button template image.
269 StopProgress,
270 /// An image of the empty trash can.
271 TrashEmpty,
272 /// An image of the full trash can.
273 TrashFull,
274 /// Permissions for a single user.
275 User,
276 /// User account toolbar icon for the preferences window.
277 UserAccounts,
278 /// Permissions for a group of users.
279 UserGroup,
280 /// Permissions for guests.
281 UserGuest,
282}