native_windows_gui2/resources/
cursor.rs

1use crate::win32::resources_helper as rh;
2use crate::{NwgError, OemCursor, OemImage};
3use std::ptr;
4use winapi::um::winnt::HANDLE;
5use winapi::um::winuser::IMAGE_CURSOR;
6
7#[cfg(feature = "embed-resource")]
8use super::EmbedResource;
9
10/**
11A wrapper over a cursor file (*.cur)
12
13Cursor resources can be used with the `cursor` feature
14
15Example:
16
17```rust
18use native_windows_gui2 as nwg;
19
20fn load_cursor() -> nwg::Cursor {
21    nwg::Cursor::from_file("Hello.cur", true).unwrap()
22}
23
24fn load_cursor_builder() -> nwg::Cursor {
25    let mut cursor = nwg::Cursor::default();
26
27    nwg::Cursor::builder()
28        .source_file(Some("Hello.cur"))
29        .strict(true)
30        .build(&mut cursor)
31        .unwrap();
32
33    cursor
34}
35
36*/
37#[allow(unused)]
38pub struct Cursor {
39    pub handle: HANDLE,
40    pub(crate) owned: bool,
41}
42
43impl Cursor {
44    pub fn builder<'a>() -> CursorBuilder<'a> {
45        CursorBuilder {
46            source_text: None,
47            source_system: None,
48            size: None,
49
50            #[cfg(feature = "embed-resource")]
51            source_embed: None,
52
53            #[cfg(feature = "embed-resource")]
54            source_embed_id: 0,
55
56            #[cfg(feature = "embed-resource")]
57            source_embed_str: None,
58
59            strict: false,
60        }
61    }
62
63    pub fn from_system(cursor: OemCursor) -> Cursor {
64        let mut out = Self::default();
65
66        // Default cursor creation cannot fail
67        Self::builder()
68            .source_system(Some(cursor))
69            .build(&mut out)
70            .unwrap();
71
72        out
73    }
74
75    /**
76        Single line helper function over the cursor builder api.
77
78        Use a file resource.
79    */
80    pub fn from_file(path: &str, strict: bool) -> Result<Cursor, NwgError> {
81        let mut cursor = Cursor::default();
82
83        Cursor::builder()
84            .source_file(Some(path))
85            .strict(strict)
86            .build(&mut cursor)?;
87
88        Ok(cursor)
89    }
90
91    /**
92        Single line helper function over the cursor builder api.
93
94        Use an embedded resource. Either `embed_id` or `embed_str` must be defined, not both.
95
96        Requires the `embed-resource` feature.
97    */
98    #[cfg(feature = "embed-resource")]
99    pub fn from_embed(
100        embed: &EmbedResource,
101        embed_id: Option<usize>,
102        embed_str: Option<&str>,
103    ) -> Result<Cursor, NwgError> {
104        let mut bitmap = Cursor::default();
105
106        Cursor::builder()
107            .source_embed(Some(embed))
108            .source_embed_id(embed_id.unwrap_or(0))
109            .source_embed_str(embed_str)
110            .build(&mut bitmap)?;
111
112        Ok(bitmap)
113    }
114}
115
116pub struct CursorBuilder<'a> {
117    source_text: Option<&'a str>,
118    source_system: Option<OemCursor>,
119    size: Option<(u32, u32)>,
120
121    #[cfg(feature = "embed-resource")]
122    source_embed: Option<&'a EmbedResource>,
123
124    #[cfg(feature = "embed-resource")]
125    source_embed_id: usize,
126
127    #[cfg(feature = "embed-resource")]
128    source_embed_str: Option<&'a str>,
129
130    strict: bool,
131}
132
133impl<'a> CursorBuilder<'a> {
134    pub fn source_file(mut self, t: Option<&'a str>) -> CursorBuilder<'a> {
135        self.source_text = t;
136        self
137    }
138
139    pub fn source_system(mut self, t: Option<OemCursor>) -> CursorBuilder<'a> {
140        self.source_system = t;
141        self
142    }
143
144    #[cfg(feature = "embed-resource")]
145    pub fn source_embed(mut self, em: Option<&'a EmbedResource>) -> CursorBuilder<'a> {
146        self.source_embed = em;
147        self
148    }
149
150    #[cfg(feature = "embed-resource")]
151    pub fn source_embed_id(mut self, id: usize) -> CursorBuilder<'a> {
152        self.source_embed_id = id;
153        self
154    }
155
156    #[cfg(feature = "embed-resource")]
157    pub fn source_embed_str(mut self, id: Option<&'a str>) -> CursorBuilder<'a> {
158        self.source_embed_str = id;
159        self
160    }
161
162    pub fn size(mut self, s: Option<(u32, u32)>) -> CursorBuilder<'a> {
163        self.size = s;
164        self
165    }
166
167    pub fn strict(mut self, s: bool) -> CursorBuilder<'a> {
168        self.strict = s;
169        self
170    }
171
172    pub fn build(self, b: &mut Cursor) -> Result<(), NwgError> {
173        if let Some(src) = self.source_text {
174            let handle = unsafe { rh::build_image(src, self.size, self.strict, IMAGE_CURSOR)? };
175            *b = Cursor {
176                handle,
177                owned: true,
178            };
179        } else if let Some(src) = self.source_system {
180            let handle = unsafe { rh::build_oem_image(OemImage::Cursor(src), self.size)? };
181            *b = Cursor {
182                handle,
183                owned: true,
184            };
185        } else {
186            #[cfg(feature = "embed-resource")]
187            fn build_embed(builder: CursorBuilder) -> Result<Cursor, NwgError> {
188                match builder.source_embed {
189                    Some(embed) => match builder.source_embed_str {
190                        Some(src) => embed.cursor_str(src).ok_or_else(|| {
191                            NwgError::resource_create(format!(
192                                "No cursor in embed resource identified by {}",
193                                src
194                            ))
195                        }),
196                        None => embed.cursor(builder.source_embed_id).ok_or_else(|| {
197                            NwgError::resource_create(format!(
198                                "No cursor in embed resource identified by {}",
199                                builder.source_embed_id
200                            ))
201                        }),
202                    },
203                    None => Err(NwgError::resource_create("No source provided for Cursor")),
204                }
205            }
206
207            #[cfg(not(feature = "embed-resource"))]
208            fn build_embed(_builder: CursorBuilder) -> Result<Cursor, NwgError> {
209                Err(NwgError::resource_create("No source provided for Cursor"))
210            }
211
212            *b = build_embed(self)?;
213        }
214
215        Ok(())
216    }
217}
218
219impl Default for Cursor {
220    fn default() -> Cursor {
221        Cursor {
222            handle: ptr::null_mut(),
223            owned: false,
224        }
225    }
226}
227
228impl PartialEq for Cursor {
229    fn eq(&self, other: &Self) -> bool {
230        self.handle == other.handle
231    }
232}
233
234impl Drop for Cursor {
235    fn drop(&mut self) {
236        if self.owned && !self.handle.is_null() {
237            rh::destroy_cursor(self.handle);
238        }
239    }
240}