pub const PRIORITY_DEFAULT: u8 = 0;
pub const PRIORITY_WIDGET: u8 = 100;
pub const PRIORITY_DRAG: u8 = 150;
pub const PRIORITY_MODAL: u8 = 200;
pub const PRIORITY_SYSTEM: u8 = 255;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
pub enum CursorIcon {
#[default]
Default,
None,
ContextMenu,
Help,
PointingHand,
Progress,
Wait,
Cell,
Crosshair,
Text,
VerticalText,
Alias,
Copy,
Move,
NoDrop,
NotAllowed,
Grab,
Grabbing,
AllScroll,
ResizeHorizontal,
ResizeVertical,
ResizeNeSw,
ResizeNwSe,
ResizeEast,
ResizeWest,
ResizeNorth,
ResizeSouth,
ResizeNorthEast,
ResizeNorthWest,
ResizeSouthEast,
ResizeSouthWest,
ResizeColumn,
ResizeRow,
ZoomIn,
ZoomOut,
}
impl CursorIcon {
pub fn is_resize(&self) -> bool {
matches!(
self,
CursorIcon::AllScroll
| CursorIcon::ResizeHorizontal
| CursorIcon::ResizeVertical
| CursorIcon::ResizeNeSw
| CursorIcon::ResizeNwSe
| CursorIcon::ResizeEast
| CursorIcon::ResizeWest
| CursorIcon::ResizeNorth
| CursorIcon::ResizeSouth
| CursorIcon::ResizeNorthEast
| CursorIcon::ResizeNorthWest
| CursorIcon::ResizeSouthEast
| CursorIcon::ResizeSouthWest
| CursorIcon::ResizeColumn
| CursorIcon::ResizeRow
)
}
pub fn is_drag(&self) -> bool {
matches!(self, CursorIcon::Grab | CursorIcon::Grabbing | CursorIcon::Move)
}
pub fn css_name(&self) -> &'static str {
match self {
CursorIcon::Default => "default",
CursorIcon::None => "none",
CursorIcon::ContextMenu => "context-menu",
CursorIcon::Help => "help",
CursorIcon::PointingHand => "pointer",
CursorIcon::Progress => "progress",
CursorIcon::Wait => "wait",
CursorIcon::Cell => "cell",
CursorIcon::Crosshair => "crosshair",
CursorIcon::Text => "text",
CursorIcon::VerticalText => "vertical-text",
CursorIcon::Alias => "alias",
CursorIcon::Copy => "copy",
CursorIcon::Move => "move",
CursorIcon::NoDrop => "no-drop",
CursorIcon::NotAllowed => "not-allowed",
CursorIcon::Grab => "grab",
CursorIcon::Grabbing => "grabbing",
CursorIcon::AllScroll => "all-scroll",
CursorIcon::ResizeHorizontal => "ew-resize",
CursorIcon::ResizeVertical => "ns-resize",
CursorIcon::ResizeNeSw => "nesw-resize",
CursorIcon::ResizeNwSe => "nwse-resize",
CursorIcon::ResizeEast => "e-resize",
CursorIcon::ResizeWest => "w-resize",
CursorIcon::ResizeNorth => "n-resize",
CursorIcon::ResizeSouth => "s-resize",
CursorIcon::ResizeNorthEast => "ne-resize",
CursorIcon::ResizeNorthWest => "nw-resize",
CursorIcon::ResizeSouthEast => "se-resize",
CursorIcon::ResizeSouthWest => "sw-resize",
CursorIcon::ResizeColumn => "col-resize",
CursorIcon::ResizeRow => "row-resize",
CursorIcon::ZoomIn => "zoom-in",
CursorIcon::ZoomOut => "zoom-out",
}
}
}
#[derive(Clone, Debug)]
pub struct CursorState {
requested: CursorIcon,
priority: u8,
}
impl Default for CursorState {
fn default() -> Self {
Self::new()
}
}
impl CursorState {
pub fn new() -> Self {
Self {
requested: CursorIcon::Default,
priority: PRIORITY_DEFAULT,
}
}
pub fn set(&mut self, icon: CursorIcon) {
self.set_with_priority(icon, PRIORITY_WIDGET);
}
pub fn set_with_priority(&mut self, icon: CursorIcon, priority: u8) {
if priority >= self.priority {
self.requested = icon;
self.priority = priority;
}
}
pub fn get(&self) -> CursorIcon {
self.requested
}
pub fn reset(&mut self) {
self.requested = CursorIcon::Default;
self.priority = PRIORITY_DEFAULT;
}
pub fn is_default(&self) -> bool {
self.requested == CursorIcon::Default
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cursor_state_new() {
let state = CursorState::new();
assert_eq!(state.get(), CursorIcon::Default);
assert!(state.is_default());
}
#[test]
fn test_cursor_state_set() {
let mut state = CursorState::new();
state.set(CursorIcon::PointingHand);
assert_eq!(state.get(), CursorIcon::PointingHand);
assert!(!state.is_default());
}
#[test]
fn test_cursor_state_reset() {
let mut state = CursorState::new();
state.set(CursorIcon::Grab);
assert!(!state.is_default());
state.reset();
assert_eq!(state.get(), CursorIcon::Default);
assert!(state.is_default());
}
#[test]
fn test_cursor_priority_override() {
let mut state = CursorState::new();
state.set_with_priority(CursorIcon::PointingHand, PRIORITY_WIDGET);
assert_eq!(state.get(), CursorIcon::PointingHand);
state.set_with_priority(CursorIcon::Grab, PRIORITY_DRAG);
assert_eq!(state.get(), CursorIcon::Grab);
state.set_with_priority(CursorIcon::Text, PRIORITY_WIDGET);
assert_eq!(state.get(), CursorIcon::Grab);
state.set_with_priority(CursorIcon::Grabbing, PRIORITY_DRAG);
assert_eq!(state.get(), CursorIcon::Grabbing);
state.set_with_priority(CursorIcon::Wait, PRIORITY_SYSTEM);
assert_eq!(state.get(), CursorIcon::Wait);
}
#[test]
fn test_cursor_icon_is_resize() {
assert!(CursorIcon::ResizeHorizontal.is_resize());
assert!(CursorIcon::ResizeVertical.is_resize());
assert!(CursorIcon::ResizeNeSw.is_resize());
assert!(CursorIcon::ResizeNwSe.is_resize());
assert!(CursorIcon::ResizeEast.is_resize());
assert!(CursorIcon::ResizeWest.is_resize());
assert!(CursorIcon::ResizeNorth.is_resize());
assert!(CursorIcon::ResizeSouth.is_resize());
assert!(CursorIcon::ResizeNorthEast.is_resize());
assert!(CursorIcon::ResizeNorthWest.is_resize());
assert!(CursorIcon::ResizeSouthEast.is_resize());
assert!(CursorIcon::ResizeSouthWest.is_resize());
assert!(CursorIcon::ResizeColumn.is_resize());
assert!(CursorIcon::ResizeRow.is_resize());
assert!(CursorIcon::AllScroll.is_resize());
assert!(!CursorIcon::Default.is_resize());
assert!(!CursorIcon::PointingHand.is_resize());
assert!(!CursorIcon::Grab.is_resize());
assert!(!CursorIcon::Text.is_resize());
}
#[test]
fn test_cursor_icon_is_drag() {
assert!(CursorIcon::Grab.is_drag());
assert!(CursorIcon::Grabbing.is_drag());
assert!(CursorIcon::Move.is_drag());
assert!(!CursorIcon::Default.is_drag());
assert!(!CursorIcon::PointingHand.is_drag());
assert!(!CursorIcon::ResizeHorizontal.is_drag());
assert!(!CursorIcon::Copy.is_drag());
}
#[test]
fn test_cursor_icon_css_name() {
assert_eq!(CursorIcon::Default.css_name(), "default");
assert_eq!(CursorIcon::None.css_name(), "none");
assert_eq!(CursorIcon::PointingHand.css_name(), "pointer");
assert_eq!(CursorIcon::Grab.css_name(), "grab");
assert_eq!(CursorIcon::Grabbing.css_name(), "grabbing");
assert_eq!(CursorIcon::Move.css_name(), "move");
assert_eq!(CursorIcon::Text.css_name(), "text");
assert_eq!(CursorIcon::ResizeHorizontal.css_name(), "ew-resize");
assert_eq!(CursorIcon::ResizeVertical.css_name(), "ns-resize");
assert_eq!(CursorIcon::ResizeNeSw.css_name(), "nesw-resize");
assert_eq!(CursorIcon::ResizeNwSe.css_name(), "nwse-resize");
assert_eq!(CursorIcon::Wait.css_name(), "wait");
assert_eq!(CursorIcon::Progress.css_name(), "progress");
assert_eq!(CursorIcon::NotAllowed.css_name(), "not-allowed");
assert_eq!(CursorIcon::ZoomIn.css_name(), "zoom-in");
assert_eq!(CursorIcon::ZoomOut.css_name(), "zoom-out");
}
#[test]
fn test_default_priority_constant() {
let mut state = CursorState::new();
state.set(CursorIcon::PointingHand);
assert_eq!(state.priority, PRIORITY_WIDGET);
}
#[test]
fn test_cursor_state_default_trait() {
let state = CursorState::default();
assert_eq!(state.get(), CursorIcon::Default);
assert!(state.is_default());
}
#[test]
fn test_cursor_icon_default_trait() {
let icon = CursorIcon::default();
assert_eq!(icon, CursorIcon::Default);
}
}