1 | // SPDX-License-Identifier: MIT OR Apache-2.0 OR Zlib |
2 | |
3 | #![cfg_attr (not(feature = "std" ), no_std)] |
4 | #![deny (rust_2018_idioms)] |
5 | #![deny (rustdoc::broken_intra_doc_links)] |
6 | #![deny (unsafe_op_in_unsafe_fn)] |
7 | #![deny (improper_ctypes, improper_ctypes_definitions)] |
8 | #![deny (clippy::all)] |
9 | #![deny (missing_debug_implementations)] |
10 | #![deny (missing_docs)] |
11 | #![forbid (unsafe_code)] |
12 | #![cfg_attr (feature = "cargo-clippy" , deny(warnings))] |
13 | #![cfg_attr (docsrs, feature(doc_auto_cfg))] |
14 | |
15 | //! The cross platform cursor icon type. |
16 | //! |
17 | //! This type is intended to be used as a standard interopability type between |
18 | //! GUI frameworks in order to convey the cursor icon type. |
19 | //! |
20 | //! # Example |
21 | //! |
22 | //! ``` |
23 | //! use cursor_icon::CursorIcon; |
24 | //! |
25 | //! # fn main() -> Result<(), Box<dyn std::error::Error>> { |
26 | //! // Parse a cursor icon from the string that describes it. |
27 | //! let cursor_name = "pointer" ; |
28 | //! let cursor_icon: CursorIcon = cursor_name.parse()?; |
29 | //! println!("The cursor icon is {:?}" , cursor_icon); |
30 | //! # Ok(()) |
31 | //! # } |
32 | //! ``` |
33 | |
34 | // This file contains a portion of the CSS Basic User Interface Module Level 3 |
35 | // specification. In particular, the names for the cursor from the #cursor |
36 | // section and documentation for some of the variants were taken. |
37 | // |
38 | // The original document is https://www.w3.org/TR/css-ui-3/#cursor. |
39 | // Copyright © 2018 W3C® (MIT, ERCIM, Keio, Beihang) |
40 | // |
41 | // These documents were used under the terms of the following license. This W3C |
42 | // license as well as the W3C short notice apply to the `CursorIcon` enum's |
43 | // variants and documentation attached to them. |
44 | |
45 | // --------- BEGGINING OF W3C LICENSE |
46 | // -------------------------------------------------------------- |
47 | // |
48 | // License |
49 | // |
50 | // By obtaining and/or copying this work, you (the licensee) agree that you have |
51 | // read, understood, and will comply with the following terms and conditions. |
52 | // |
53 | // Permission to copy, modify, and distribute this work, with or without |
54 | // modification, for any purpose and without fee or royalty is hereby granted, |
55 | // provided that you include the following on ALL copies of the work or portions |
56 | // thereof, including modifications: |
57 | // |
58 | // - The full text of this NOTICE in a location viewable to users of the |
59 | // redistributed or derivative work. |
60 | // - Any pre-existing intellectual property disclaimers, notices, or terms and |
61 | // conditions. If none exist, the W3C Software and Document Short Notice |
62 | // should be included. |
63 | // - Notice of any changes or modifications, through a copyright statement on |
64 | // the new code or document such as "This software or document includes |
65 | // material copied from or derived from [title and URI of the W3C document]. |
66 | // Copyright © [YEAR] W3C® (MIT, ERCIM, Keio, Beihang)." |
67 | // |
68 | // Disclaimers |
69 | // |
70 | // THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS |
71 | // OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES |
72 | // OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF |
73 | // THE SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, |
74 | // COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. |
75 | // |
76 | // COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR |
77 | // CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. |
78 | // |
79 | // The name and trademarks of copyright holders may NOT be used in advertising |
80 | // or publicity pertaining to the work without specific, written prior |
81 | // permission. Title to copyright in this work will at all times remain with |
82 | // copyright holders. |
83 | // |
84 | // --------- END OF W3C LICENSE |
85 | // -------------------------------------------------------------------- |
86 | |
87 | // --------- BEGGINING OF W3C SHORT NOTICE |
88 | // --------------------------------------------------------- |
89 | // |
90 | // winit: https://github.com/rust-windowing/cursor-icon |
91 | // |
92 | // Copyright © 2023 World Wide Web Consortium, (Massachusetts Institute of |
93 | // Technology, European Research Consortium for Informatics and Mathematics, |
94 | // Keio University, Beihang). All Rights Reserved. This work is distributed |
95 | // under the W3C® Software License [1] in the hope that it will be useful, but |
96 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
97 | // FITNESS FOR A PARTICULAR PURPOSE. |
98 | // |
99 | // [1] http://www.w3.org/Consortium/Legal/copyright-software |
100 | // |
101 | // --------- END OF W3C SHORT NOTICE |
102 | // -------------------------------------------------------------- |
103 | |
104 | #[cfg (feature = "serde" )] |
105 | #[macro_use ] |
106 | extern crate serde; |
107 | |
108 | // XXX for forwards compatibility. |
109 | #[cfg (feature = "alloc" )] |
110 | extern crate alloc as _; |
111 | |
112 | /// Describes the appearance of the (usually mouse) cursor icon. |
113 | /// |
114 | /// The names are taken from the CSS W3C specification: |
115 | /// <https://www.w3.org/TR/css-ui-3/#cursor> |
116 | /// |
117 | /// # Examples |
118 | /// |
119 | /// ``` |
120 | /// use cursor_icon::CursorIcon; |
121 | /// |
122 | /// // Get the cursor icon for the default cursor. |
123 | /// let cursor_icon = CursorIcon::Default; |
124 | /// ``` |
125 | #[non_exhaustive ] |
126 | #[derive (Debug, Default, Copy, Clone, PartialEq, Eq, Hash)] |
127 | #[cfg_attr (feature = "serde" , derive(Serialize, Deserialize))] |
128 | pub enum CursorIcon { |
129 | /// The platform-dependent default cursor. Often rendered as arrow. |
130 | #[default] |
131 | Default, |
132 | |
133 | /// A context menu is available for the object under the cursor. Often |
134 | /// rendered as an arrow with a small menu-like graphic next to it. |
135 | ContextMenu, |
136 | |
137 | /// Help is available for the object under the cursor. Often rendered as a |
138 | /// question mark or a balloon. |
139 | Help, |
140 | |
141 | /// The cursor is a pointer that indicates a link. Often rendered as the |
142 | /// backside of a hand with the index finger extended. |
143 | Pointer, |
144 | |
145 | /// A progress indicator. The program is performing some processing, but is |
146 | /// different from [`CursorIcon::Wait`] in that the user may still interact |
147 | /// with the program. |
148 | Progress, |
149 | |
150 | /// Indicates that the program is busy and the user should wait. Often |
151 | /// rendered as a watch or hourglass. |
152 | Wait, |
153 | |
154 | /// Indicates that a cell or set of cells may be selected. Often rendered as |
155 | /// a thick plus-sign with a dot in the middle. |
156 | Cell, |
157 | |
158 | /// A simple crosshair (e.g., short line segments resembling a "+" sign). |
159 | /// Often used to indicate a two dimensional bitmap selection mode. |
160 | Crosshair, |
161 | |
162 | /// Indicates text that may be selected. Often rendered as an I-beam. |
163 | Text, |
164 | |
165 | /// Indicates vertical-text that may be selected. Often rendered as a |
166 | /// horizontal I-beam. |
167 | VerticalText, |
168 | |
169 | /// Indicates an alias of/shortcut to something is to be created. Often |
170 | /// rendered as an arrow with a small curved arrow next to it. |
171 | Alias, |
172 | |
173 | /// Indicates something is to be copied. Often rendered as an arrow with a |
174 | /// small plus sign next to it. |
175 | Copy, |
176 | |
177 | /// Indicates something is to be moved. |
178 | Move, |
179 | |
180 | /// Indicates that the dragged item cannot be dropped at the current cursor |
181 | /// location. Often rendered as a hand or pointer with a small circle with a |
182 | /// line through it. |
183 | NoDrop, |
184 | |
185 | /// Indicates that the requested action will not be carried out. Often |
186 | /// rendered as a circle with a line through it. |
187 | NotAllowed, |
188 | |
189 | /// Indicates that something can be grabbed (dragged to be moved). Often |
190 | /// rendered as the backside of an open hand. |
191 | Grab, |
192 | |
193 | /// Indicates that something is being grabbed (dragged to be moved). Often |
194 | /// rendered as the backside of a hand with fingers closed mostly out of |
195 | /// view. |
196 | Grabbing, |
197 | |
198 | /// The east border to be moved. |
199 | EResize, |
200 | |
201 | /// The north border to be moved. |
202 | NResize, |
203 | |
204 | /// The north-east corner to be moved. |
205 | NeResize, |
206 | |
207 | /// The north-west corner to be moved. |
208 | NwResize, |
209 | |
210 | /// The south border to be moved. |
211 | SResize, |
212 | |
213 | /// The south-east corner to be moved. |
214 | SeResize, |
215 | |
216 | /// The south-west corner to be moved. |
217 | SwResize, |
218 | |
219 | /// The west border to be moved. |
220 | WResize, |
221 | |
222 | /// The east and west borders to be moved. |
223 | EwResize, |
224 | |
225 | /// The south and north borders to be moved. |
226 | NsResize, |
227 | |
228 | /// The north-east and south-west corners to be moved. |
229 | NeswResize, |
230 | |
231 | /// The north-west and south-east corners to be moved. |
232 | NwseResize, |
233 | |
234 | /// Indicates that the item/column can be resized horizontally. Often |
235 | /// rendered as arrows pointing left and right with a vertical bar |
236 | /// separating them. |
237 | ColResize, |
238 | |
239 | /// Indicates that the item/row can be resized vertically. Often rendered as |
240 | /// arrows pointing up and down with a horizontal bar separating them. |
241 | RowResize, |
242 | |
243 | /// Indicates that the something can be scrolled in any direction. Often |
244 | /// rendered as arrows pointing up, down, left, and right with a dot in the |
245 | /// middle. |
246 | AllScroll, |
247 | |
248 | /// Indicates that something can be zoomed in. Often rendered as a |
249 | /// magnifying glass with a "+" in the center of the glass. |
250 | ZoomIn, |
251 | |
252 | /// Indicates that something can be zoomed in. Often rendered as a |
253 | /// magnifying glass with a "-" in the center of the glass. |
254 | ZoomOut, |
255 | } |
256 | |
257 | impl CursorIcon { |
258 | /// The name of the cursor icon as defined in w3c standard. |
259 | /// |
260 | /// This name most of the time could be passed as is to cursor loading |
261 | /// libraries on X11/Wayland and could be used as-is on web. |
262 | /// |
263 | /// # Examples |
264 | /// |
265 | /// ```no_run |
266 | /// use cursor_icon::CursorIcon; |
267 | /// use wayland_cursor::CursorTheme; |
268 | /// |
269 | /// # use wayland_client::Connection; |
270 | /// # use wayland_client::protocol::wl_shm::WlShm; |
271 | /// # fn test(conn: &Connection, shm: WlShm) -> Result<(), Box<dyn std::error::Error>> { |
272 | /// // Choose a cursor to load. |
273 | /// let cursor = CursorIcon::Help; |
274 | /// |
275 | /// // Load the Wayland cursor theme. |
276 | /// let mut cursor_theme = CursorTheme::load(conn, shm, 32)?; |
277 | /// |
278 | /// // Load the cursor. |
279 | /// let cursor = cursor_theme.get_cursor(cursor.name()); |
280 | /// if let Some(cursor) = cursor { |
281 | /// println!("Total number of images: {}" , cursor.image_count()); |
282 | /// } |
283 | /// # Ok(()) |
284 | /// # } |
285 | /// ``` |
286 | pub fn name(&self) -> &'static str { |
287 | match self { |
288 | CursorIcon::Default => "default" , |
289 | CursorIcon::ContextMenu => "context-menu" , |
290 | CursorIcon::Help => "help" , |
291 | CursorIcon::Pointer => "pointer" , |
292 | CursorIcon::Progress => "progress" , |
293 | CursorIcon::Wait => "wait" , |
294 | CursorIcon::Cell => "cell" , |
295 | CursorIcon::Crosshair => "crosshair" , |
296 | CursorIcon::Text => "text" , |
297 | CursorIcon::VerticalText => "vertical-text" , |
298 | CursorIcon::Alias => "alias" , |
299 | CursorIcon::Copy => "copy" , |
300 | CursorIcon::Move => "move" , |
301 | CursorIcon::NoDrop => "no-drop" , |
302 | CursorIcon::NotAllowed => "not-allowed" , |
303 | CursorIcon::Grab => "grab" , |
304 | CursorIcon::Grabbing => "grabbing" , |
305 | CursorIcon::EResize => "e-resize" , |
306 | CursorIcon::NResize => "n-resize" , |
307 | CursorIcon::NeResize => "ne-resize" , |
308 | CursorIcon::NwResize => "nw-resize" , |
309 | CursorIcon::SResize => "s-resize" , |
310 | CursorIcon::SeResize => "se-resize" , |
311 | CursorIcon::SwResize => "sw-resize" , |
312 | CursorIcon::WResize => "w-resize" , |
313 | CursorIcon::EwResize => "ew-resize" , |
314 | CursorIcon::NsResize => "ns-resize" , |
315 | CursorIcon::NeswResize => "nesw-resize" , |
316 | CursorIcon::NwseResize => "nwse-resize" , |
317 | CursorIcon::ColResize => "col-resize" , |
318 | CursorIcon::RowResize => "row-resize" , |
319 | CursorIcon::AllScroll => "all-scroll" , |
320 | CursorIcon::ZoomIn => "zoom-in" , |
321 | CursorIcon::ZoomOut => "zoom-out" , |
322 | } |
323 | } |
324 | |
325 | /// A list of alternative names for the cursor icon as commonly found in |
326 | /// legacy Xcursor themes. |
327 | /// |
328 | /// This should only be used as a fallback in case the cursor theme does not |
329 | /// adhere to the w3c standard. |
330 | pub fn alt_names(&self) -> &[&'static str] { |
331 | match self { |
332 | CursorIcon::Default => &["left_ptr" , "arrow" , "top_left_arrow" , "left_arrow" ], |
333 | CursorIcon::ContextMenu => &[], |
334 | CursorIcon::Help => &["question_arrow" , "whats_this" ], |
335 | CursorIcon::Pointer => &["hand2" , "hand1" , "hand" , "pointing_hand" ], |
336 | CursorIcon::Progress => &["left_ptr_watch" , "half-busy" ], |
337 | CursorIcon::Wait => &["watch" ], |
338 | CursorIcon::Cell => &["plus" ], |
339 | CursorIcon::Crosshair => &["cross" ], |
340 | CursorIcon::Text => &["xterm" , "ibeam" ], |
341 | CursorIcon::VerticalText => &[], |
342 | CursorIcon::Alias => &["link" ], |
343 | CursorIcon::Copy => &[], |
344 | CursorIcon::Move => &[], |
345 | CursorIcon::NoDrop => &["circle" ], |
346 | CursorIcon::NotAllowed => &["crossed_circle" , "forbidden" ], |
347 | CursorIcon::Grab => &["openhand" , "fleur" ], |
348 | CursorIcon::Grabbing => &["closedhand" ], |
349 | CursorIcon::EResize => &["right_side" ], |
350 | CursorIcon::NResize => &["top_side" ], |
351 | CursorIcon::NeResize => &["top_right_corner" ], |
352 | CursorIcon::NwResize => &["top_left_corner" ], |
353 | CursorIcon::SResize => &["bottom_side" ], |
354 | CursorIcon::SeResize => &["bottom_right_corner" ], |
355 | CursorIcon::SwResize => &["bottom_left_corner" ], |
356 | CursorIcon::WResize => &["left_side" ], |
357 | CursorIcon::EwResize => &["h_double_arrow" , "size_hor" ], |
358 | CursorIcon::NsResize => &["v_double_arrow" , "size_ver" ], |
359 | CursorIcon::NeswResize => &["fd_double_arrow" , "size_bdiag" ], |
360 | CursorIcon::NwseResize => &["bd_double_arrow" , "size_fdiag" ], |
361 | CursorIcon::ColResize => &["split_h" , "h_double_arrow" , "sb_h_double_arrow" ], |
362 | CursorIcon::RowResize => &["split_v" , "v_double_arrow" , "sb_v_double_arrow" ], |
363 | CursorIcon::AllScroll => &["size_all" ], |
364 | CursorIcon::ZoomIn => &[], |
365 | CursorIcon::ZoomOut => &[], |
366 | } |
367 | } |
368 | } |
369 | |
370 | impl core::fmt::Display for CursorIcon { |
371 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
372 | f.write_str(self.name()) |
373 | } |
374 | } |
375 | |
376 | impl core::str::FromStr for CursorIcon { |
377 | type Err = ParseError; |
378 | |
379 | /// Parse a string slice into [`CursorIcon`]. |
380 | /// |
381 | /// The `name` is a lower kebab case [`CursorIcon`] varaint name, e.g. |
382 | /// `nesw-resize`. The set of possible valid `name` values matches exactly |
383 | /// the set of [`CursorIcon::name`] outputs. |
384 | fn from_str(name: &str) -> Result<Self, Self::Err> { |
385 | match name { |
386 | "default" => Ok(CursorIcon::Default), |
387 | "context-menu" => Ok(CursorIcon::ContextMenu), |
388 | "help" => Ok(CursorIcon::Help), |
389 | "pointer" => Ok(CursorIcon::Pointer), |
390 | "progress" => Ok(CursorIcon::Progress), |
391 | "wait" => Ok(CursorIcon::Wait), |
392 | "cell" => Ok(CursorIcon::Cell), |
393 | "crosshair" => Ok(CursorIcon::Crosshair), |
394 | "text" => Ok(CursorIcon::Text), |
395 | "vertical-text" => Ok(CursorIcon::VerticalText), |
396 | "alias" => Ok(CursorIcon::Alias), |
397 | "copy" => Ok(CursorIcon::Copy), |
398 | "move" => Ok(CursorIcon::Move), |
399 | "no-drop" => Ok(CursorIcon::NoDrop), |
400 | "not-allowed" => Ok(CursorIcon::NotAllowed), |
401 | "grab" => Ok(CursorIcon::Grab), |
402 | "grabbing" => Ok(CursorIcon::Grabbing), |
403 | "e-resize" => Ok(CursorIcon::EResize), |
404 | "n-resize" => Ok(CursorIcon::NResize), |
405 | "ne-resize" => Ok(CursorIcon::NeResize), |
406 | "nw-resize" => Ok(CursorIcon::NwResize), |
407 | "s-resize" => Ok(CursorIcon::SResize), |
408 | "se-resize" => Ok(CursorIcon::SeResize), |
409 | "sw-resize" => Ok(CursorIcon::SwResize), |
410 | "w-resize" => Ok(CursorIcon::WResize), |
411 | "ew-resize" => Ok(CursorIcon::EwResize), |
412 | "ns-resize" => Ok(CursorIcon::NsResize), |
413 | "nesw-resize" => Ok(CursorIcon::NeswResize), |
414 | "nwse-resize" => Ok(CursorIcon::NwseResize), |
415 | "col-resize" => Ok(CursorIcon::ColResize), |
416 | "row-resize" => Ok(CursorIcon::RowResize), |
417 | "all-scroll" => Ok(CursorIcon::AllScroll), |
418 | "zoom-in" => Ok(CursorIcon::ZoomIn), |
419 | "zoom-out" => Ok(CursorIcon::ZoomOut), |
420 | _ => Err(ParseError { _private: () }), |
421 | } |
422 | } |
423 | } |
424 | |
425 | /// An error which could be returned when parsing [`CursorIcon`]. |
426 | /// |
427 | /// This occurs when the [`FromStr`] implementation of [`CursorIcon`] fails. |
428 | /// |
429 | /// [`FromStr`]: core::str::FromStr |
430 | #[derive (Debug, PartialEq, Eq)] |
431 | pub struct ParseError { |
432 | _private: (), |
433 | } |
434 | |
435 | impl core::fmt::Display for ParseError { |
436 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
437 | f.write_str(data:"failed to parse cursor icon" ) |
438 | } |
439 | } |
440 | |
441 | #[cfg (feature = "std" )] |
442 | impl std::error::Error for ParseError {} |
443 | |