Skip to main content

native_windows_gui/resources/
cursor.rs

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