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}