native_windows_gui2/resources/
icon.rs

1use crate::win32::resources_helper as rh;
2use crate::{NwgError, OemIcon, OemImage};
3use std::ptr;
4use winapi::um::winnt::HANDLE;
5use winapi::um::winuser::IMAGE_ICON;
6
7#[cfg(feature = "embed-resource")]
8use super::EmbedResource;
9
10/**
11A wrapper over a icon file (*.ico)
12
13Windows icons are a legacy thing and should only be used when winapi forces you to use them (ex: when setting a window icon).
14The `Bitmap` object of NWG not only supports transparency if "image-decoder" is enabled but it can also be create from multiple
15different sources (including ".ico" files).
16
17To display a icon in an application, see the `ImageFrame` control.
18
19Note: Loading an icon from binary source (source_bin) REQUIRES the "image-decoder" feature.
20
21**Builder parameters:**
22  * `source_file`:      The source of the icon if it is a file.
23  * `source_bin`:       The source of the icon if it is a binary blob. For example using `include_bytes!("my_icon.ico")`.
24  * `source_system`:    The source of the icon if it is a system resource (see OemIcon)
25  * `source_embed`:     The source of the icon if it is stored in an embedded file
26  * `source_embed_id`:  The number identifier of the icon in the embedded file
27  * `source_embed_str`: The string identifier of the icon in the embedded file
28  * `size`:             Optional. Resize the image to this size.
29  * `strict`:           Use a system placeholder instead of panicking if the image source do no exists.
30
31Example:
32
33```rust
34use native_windows_gui2 as nwg;
35
36fn load_icon() -> nwg::Icon {
37    nwg::Icon::from_file("hello.ico", true).unwrap()
38}
39
40fn load_icon_builder() -> nwg::Icon {
41    let mut icon = nwg::Icon::default();
42
43    nwg::Icon::builder()
44        .source_file(Some("hello.ico"))
45        .strict(true)
46        .build(&mut icon);
47
48    icon
49}
50
51*/
52#[allow(unused)]
53pub struct Icon {
54    pub handle: HANDLE,
55    pub(crate) owned: bool,
56}
57
58impl Icon {
59    pub fn builder<'a>() -> IconBuilder<'a> {
60        IconBuilder {
61            source_text: None,
62            source_bin: None,
63            source_system: None,
64
65            #[cfg(feature = "embed-resource")]
66            source_embed: None,
67
68            #[cfg(feature = "embed-resource")]
69            source_embed_id: 0,
70
71            #[cfg(feature = "embed-resource")]
72            source_embed_str: None,
73
74            size: None,
75            strict: false,
76        }
77    }
78
79    /**
80        Single line helper function over the icon builder api.
81
82        Use system resources.
83    */
84    pub fn from_system(sys_icon: OemIcon) -> Icon {
85        let mut icon = Self::default();
86
87        // Default icon creation cannot fail
88        Self::builder()
89            .source_system(Some(sys_icon))
90            .build(&mut icon)
91            .unwrap();
92
93        icon
94    }
95
96    /**
97        Single line helper function over the icon builder api.
98
99        Use a file resource.
100    */
101    pub fn from_file(path: &str, strict: bool) -> Result<Icon, NwgError> {
102        let mut icon = Icon::default();
103
104        Icon::builder()
105            .source_file(Some(path))
106            .strict(strict)
107            .build(&mut icon)?;
108
109        Ok(icon)
110    }
111
112    /**
113        Single line helper function over the icon builder api.
114
115        Use a binary resource.
116    */
117    pub fn from_bin(bin: &[u8]) -> Result<Icon, NwgError> {
118        let mut icon = Icon::default();
119
120        Icon::builder().source_bin(Some(bin)).build(&mut icon)?;
121
122        Ok(icon)
123    }
124
125    /**
126        Single line helper function over the icon builder api.
127
128        Use an embedded resource. Either `embed_id` or `embed_str` must be defined, not both.
129
130        Requires the `embed-resource` feature.
131    */
132    #[cfg(feature = "embed-resource")]
133    pub fn from_embed(
134        embed: &EmbedResource,
135        embed_id: Option<usize>,
136        embed_str: Option<&str>,
137    ) -> Result<Icon, NwgError> {
138        let mut icon = Icon::default();
139
140        Icon::builder()
141            .source_embed(Some(embed))
142            .source_embed_id(embed_id.unwrap_or(0))
143            .source_embed_str(embed_str)
144            .build(&mut icon)?;
145
146        Ok(icon)
147    }
148}
149
150pub struct IconBuilder<'a> {
151    source_text: Option<&'a str>,
152    source_bin: Option<&'a [u8]>,
153    source_system: Option<OemIcon>,
154
155    #[cfg(feature = "embed-resource")]
156    source_embed: Option<&'a EmbedResource>,
157
158    #[cfg(feature = "embed-resource")]
159    source_embed_id: usize,
160
161    #[cfg(feature = "embed-resource")]
162    source_embed_str: Option<&'a str>,
163
164    size: Option<(u32, u32)>,
165    strict: bool,
166}
167
168impl<'a> IconBuilder<'a> {
169    pub fn source_file(mut self, t: Option<&'a str>) -> IconBuilder<'a> {
170        self.source_text = t;
171        self
172    }
173
174    pub fn source_bin(mut self, t: Option<&'a [u8]>) -> IconBuilder<'a> {
175        self.source_bin = t;
176        self
177    }
178
179    pub fn source_system(mut self, t: Option<OemIcon>) -> IconBuilder<'a> {
180        self.source_system = t;
181        self
182    }
183
184    #[cfg(feature = "embed-resource")]
185    pub fn source_embed(mut self, em: Option<&'a EmbedResource>) -> IconBuilder<'a> {
186        self.source_embed = em;
187        self
188    }
189
190    #[cfg(feature = "embed-resource")]
191    pub fn source_embed_id(mut self, id: usize) -> IconBuilder<'a> {
192        self.source_embed_id = id;
193        self
194    }
195
196    #[cfg(feature = "embed-resource")]
197    pub fn source_embed_str(mut self, id: Option<&'a str>) -> IconBuilder<'a> {
198        self.source_embed_str = id;
199        self
200    }
201
202    pub fn size(mut self, s: Option<(u32, u32)>) -> IconBuilder<'a> {
203        self.size = s;
204        self
205    }
206
207    pub fn strict(mut self, s: bool) -> IconBuilder<'a> {
208        self.strict = s;
209        self
210    }
211
212    pub fn build(self, b: &mut Icon) -> Result<(), NwgError> {
213        if let Some(src) = self.source_text {
214            let handle = unsafe { rh::build_image(src, self.size, self.strict, IMAGE_ICON)? };
215            *b = Icon {
216                handle,
217                owned: true,
218            };
219        } else if let Some(src) = self.source_system {
220            let handle = unsafe { rh::build_oem_image(OemImage::Icon(src), self.size)? };
221            *b = Icon {
222                handle,
223                owned: true,
224            };
225        } else if let Some(src) = self.source_bin {
226            let handle = unsafe { rh::icon_from_memory(src, self.strict, self.size)? };
227            *b = Icon {
228                handle,
229                owned: true,
230            };
231        } else {
232            #[cfg(feature = "embed-resource")]
233            fn build_embed(builder: IconBuilder) -> Result<Icon, NwgError> {
234                match builder.source_embed {
235                    Some(embed) => match builder.source_embed_str {
236                        Some(src) => embed.icon_str(src, builder.size).ok_or_else(|| {
237                            NwgError::resource_create(format!(
238                                "No icon in embed resource identified by {}",
239                                src
240                            ))
241                        }),
242                        None => embed
243                            .icon(builder.source_embed_id, builder.size)
244                            .ok_or_else(|| {
245                                NwgError::resource_create(format!(
246                                    "No icon in embed resource identified by {}",
247                                    builder.source_embed_id
248                                ))
249                            }),
250                    },
251                    None => Err(NwgError::resource_create("No source provided for Icon")),
252                }
253            }
254
255            #[cfg(not(feature = "embed-resource"))]
256            fn build_embed(_builder: IconBuilder) -> Result<Icon, NwgError> {
257                Err(NwgError::resource_create("No source provided for Icon"))
258            }
259
260            *b = build_embed(self)?;
261        }
262
263        Ok(())
264    }
265}
266
267impl Default for Icon {
268    fn default() -> Icon {
269        Icon {
270            handle: ptr::null_mut(),
271            owned: false,
272        }
273    }
274}
275
276// impl Drop for Icon {
277//
278//     fn drop(&mut self) {
279//         if self.owned && !self.handle.is_null() {
280//             rh::destroy_icon(self.handle);
281//         }
282//     }
283//
284// }
285
286impl PartialEq for Icon {
287    fn eq(&self, other: &Self) -> bool {
288        self.handle == other.handle
289    }
290}