#[cfg(all(feature = "system", target_os = "windows"))]
#[cfg(feature = "svg")]
pub use cursors_windows::load_base_cursor_with_file;
#[cfg(feature = "keycodes")]
use crate::platform::windowing::WindowError;
use crate::{extensions::*, prelude::Buffer};
#[cfg(feature = "svg")]
pub mod cursor_glfw;
#[cfg(target_os = "windows")]
#[cfg(feature = "svg")]
#[cfg(feature = "system")]
pub mod cursors_windows;
#[cfg(feature = "system")]
pub mod position;
pub const trait CursorManager {
fn load_cursor(
&mut self,
name: &str,
size: U2,
image_data: Buffer,
hotspot_x: u16,
hotspot_y: u16,
);
fn get_cursor(&self, name: &str) -> Cursor;
fn load_builtin_cursors(
&mut self,
size: U2,
main_color: u32,
secondary_color: u32,
);
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub enum Cursor {
#[cfg(target_os = "windows")]
#[cfg(feature = "svg")]
#[cfg(feature = "system")]
Win(windows::Win32::UI::WindowsAndMessaging::HCURSOR),
#[cfg(target_os = "linux")]
X11(u64), #[cfg(target_os = "macos")]
Mac(*mut std::ffi::c_void), Glfw((Buffer, u32, u32)),
}
pub const trait SetSelfToCursor {
fn set(&mut self, cursor: &Cursor);
}
impl SetSelfToCursor for Cursor {
fn set(&mut self, cursor: &Cursor) {
*self = cursor.clone();
}
}
impl SetSelfToCursor for Option<Cursor> {
fn set(&mut self, cursor: &Cursor) {
*self = Some(cursor.clone());
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub struct Cursors {
pub alias: Cursor,
pub all_scroll: Cursor,
pub bottom_left_corner: Cursor,
pub arrow_bottom_right: Cursor,
pub side_bottom: Cursor,
pub cell: Cursor,
pub centered_pointer: Cursor,
pub col_resize: Cursor,
pub color_picker: Cursor,
pub context_menu: Cursor,
pub copy: Cursor,
pub crosshair: Cursor,
pub default: Cursor,
pub closed_hand: Cursor,
pub closed_hand_no_drop: Cursor,
pub arrow_down: Cursor,
pub draft: Cursor,
pub fleur: Cursor,
pub help: Cursor,
pub arrow_left: Cursor,
pub side_left: Cursor,
pub no_drop: Cursor,
pub not_allowed: Cursor,
pub open_hand: Cursor,
pub pencil: Cursor,
pub pirate: Cursor,
pub pointer: Cursor,
pub arrow_right: Cursor,
pub mirrored_pointer: Cursor,
pub side_right: Cursor,
pub size_nesw: Cursor,
pub size_nwse: Cursor,
pub size_hor: Cursor,
pub size_ver: Cursor,
pub text: Cursor,
pub arrow_top_left: Cursor,
pub arrow_top_right: Cursor,
pub side_top: Cursor,
pub arrow_up: Cursor,
pub vertical_text: Cursor,
pub zoom_in: Cursor,
pub zoom_out: Cursor,
}
#[cfg(feature = "svg")]
#[cfg(all(feature = "system", target_os = "windows"))]
impl Cursors {
#[allow(clippy::too_many_lines)]
pub fn load<F>(
size: CursorResolution,
main_color: u32,
secondary_color: u32,
load_base_cursor_with_file: F,
) -> Result<Self, String>
where
F: Fn(
BaseCursor,
CursorResolution,
String,
) -> Result<Cursor, LoadCursorError>,
{
let default = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 6,
hot_spot_y: 4,
},
size,
include_str!("./svg/default.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "default.svg".to_string())?;
let alias = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 6,
hot_spot_y: 4,
},
size,
include_str!("./svg/alias.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "alias.svg".to_string())?;
let all_scroll = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 16,
},
size,
include_str!("./svg/all-scroll.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "all-scroll.svg".to_string())?;
let bottom_left_corner = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 5,
hot_spot_y: 27,
},
size,
include_str!("./svg/bottom_left_corner.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "bottom_left_corner.svg".to_string())?;
let arrow_bottom_right = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 29,
hot_spot_y: 27,
},
size,
include_str!("./svg/bottom_right_corner.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "bottom_right_corner.svg".to_string())?;
let side_bottom = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 28,
},
size,
include_str!("./svg/bottom_side.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "bottom_side.svg".to_string())?;
let cell = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 16,
},
size,
include_str!("./svg/cell.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "cell.svg".to_string())?;
let centered_pointer = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 15,
hot_spot_y: 7,
},
size,
include_str!("./svg/center_ptr.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "center_ptr.svg".to_string())?;
let col_resize = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 16,
},
size,
include_str!("./svg/col-resize.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "col-resize.svg".to_string())?;
let color_picker = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 4,
hot_spot_y: 29,
},
size,
include_str!("./svg/color-picker.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "color-picker.svg".to_string())?;
let context_menu = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 6,
hot_spot_y: 4,
},
size,
include_str!("./svg/context-menu.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "context-menu.svg".to_string())?;
let copy = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 6,
hot_spot_y: 4,
},
size,
include_str!("./svg/copy.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "copy.svg".to_string())?;
let crosshair = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 16,
},
size,
include_str!("./svg/crosshair.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "crosshair.svg".to_string())?;
let closed_hand = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 16,
},
size,
include_str!("./svg/closed-hand.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "closed-hand.svg".to_string())?;
let closed_hand_no_drop = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 16,
},
size,
include_str!("./svg/closed-hand-no-drop.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "closed-hand-no-drop.svg".to_string())?;
let arrow_down = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 28,
},
size,
include_str!("./svg/down-arrow.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "down-arrow.svg".to_string())?;
let draft = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 4,
hot_spot_y: 29,
},
size,
include_str!("./svg/draft.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "draft.svg".to_string())?;
let fleur = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 16,
},
size,
include_str!("./svg/fleur.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "fleur.svg".to_string())?;
let help = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 4,
hot_spot_y: 4,
},
size,
include_str!("./svg/help.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "help.svg".to_string())?;
let arrow_left = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 4,
hot_spot_y: 16,
},
size,
include_str!("./svg/left-arrow.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "left-arrow.svg".to_string())?;
let side_left = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 4,
hot_spot_y: 16,
},
size,
include_str!("./svg/left_side.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "left_side.svg".to_string())?;
let no_drop = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 6,
hot_spot_y: 4,
},
size,
include_str!("./svg/no-drop.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "no-drop.svg".to_string())?;
let not_allowed = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 16,
},
size,
include_str!("./svg/not-allowed.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "not-allowed.svg".to_string())?;
let open_hand = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 16,
},
size,
include_str!("./svg/open-hand.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "open-hand.svg".to_string())?;
let pencil = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 4,
hot_spot_y: 29,
},
size,
include_str!("./svg/pencil.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "pencil.svg".to_string())?;
let pirate = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 16,
},
size,
include_str!("./svg/pirate.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "pirate.svg".to_string())?;
let pointer = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 13,
hot_spot_y: 7,
},
size,
include_str!("./svg/pointer.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "pointer.svg".to_string())?;
let arrow_right = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 28,
hot_spot_y: 16,
},
size,
include_str!("./svg/right-arrow.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "right-arrow.svg".to_string())?;
let mirrored_pointer = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 28,
hot_spot_y: 4,
},
size,
include_str!("./svg/right_ptr.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "right_ptr.svg".to_string())?;
let side_right = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 28,
hot_spot_y: 16,
},
size,
include_str!("./svg/right_side.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "right_side.svg".to_string())?;
let size_nesw = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 16,
},
size,
include_str!("./svg/size_nesw.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "size_nesw.svg".to_string())?;
let size_nwse = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 16,
},
size,
include_str!("./svg/size_nwse.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "size_nwse.svg".to_string())?;
let size_hor = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 16,
},
size,
include_str!("./svg/size_hor.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "size_hor.svg".to_string())?;
let size_ver = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 16,
},
size,
include_str!("./svg/size_ver.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "size_ver.svg".to_string())?;
let text = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 15,
hot_spot_y: 16,
},
size,
include_str!("./svg/text.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "text.svg".to_string())?;
let arrow_top_left = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 9,
hot_spot_y: 9,
},
size,
include_str!("./svg/top_left_corner.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "top_left_corner.svg".to_string())?;
let arrow_top_right = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 21,
hot_spot_y: 9,
},
size,
include_str!("./svg/top_right_corner.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "top_right_corner.svg".to_string())?;
let side_top = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 4,
},
size,
include_str!("./svg/top_side.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "top_side.svg".to_string())?;
let arrow_up = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 4,
},
size,
include_str!("./svg/up-arrow.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "up-arrow.svg".to_string())?;
let vertical_text = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 16,
},
size,
include_str!("./svg/vertical-text.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "vertical-text.svg".to_string())?;
let zoom_in = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 16,
},
size,
include_str!("./svg/zoom-in.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "zoom-in.svg".to_string())?;
let zoom_out = load_base_cursor_with_file(
BaseCursor {
hot_spot_x: 16,
hot_spot_y: 16,
},
size,
include_str!("./svg/zoom-out.svg")
.to_string()
.replace(
"{main}",
&crate::graphics::u32_to_hex_without_alpha(main_color),
)
.replace(
"{secondary}",
&crate::graphics::u32_to_hex_without_alpha(secondary_color),
),
)
.map_err(|_| "zoom-out.svg".to_string())?;
Ok(Self {
alias,
all_scroll,
bottom_left_corner,
arrow_bottom_right,
side_bottom,
cell,
centered_pointer,
col_resize,
color_picker,
context_menu,
copy,
crosshair,
default,
closed_hand,
closed_hand_no_drop,
arrow_down,
draft,
fleur,
help,
arrow_left,
side_left,
no_drop,
not_allowed,
open_hand,
pencil,
pirate,
pointer,
arrow_right,
mirrored_pointer,
side_right,
size_nesw,
size_nwse,
size_hor,
size_ver,
text,
arrow_top_left,
arrow_top_right,
side_top,
arrow_up,
vertical_text,
zoom_in,
zoom_out,
})
}
#[must_use]
pub const fn from_cursor_style(
&self,
style: crate::platform::CursorStyle,
) -> &Cursor {
use crate::platform::CursorStyle;
match style {
CursorStyle::Alias => &self.alias,
CursorStyle::AllScroll => &self.all_scroll,
CursorStyle::ArrowBottomLeft => &self.bottom_left_corner,
CursorStyle::ArrowBottomRight => &self.arrow_bottom_right,
CursorStyle::SideBottom => &self.side_bottom,
CursorStyle::Cell => &self.cell,
CursorStyle::CenteredPointer => &self.centered_pointer,
CursorStyle::ResizeHorizontally => &self.col_resize,
CursorStyle::ColorPicker => &self.color_picker,
CursorStyle::ContextMenu => &self.context_menu,
CursorStyle::Copy => &self.copy,
CursorStyle::Crosshair => &self.crosshair,
CursorStyle::Default => &self.default,
CursorStyle::HandClosed => &self.closed_hand,
CursorStyle::HandClosedNoDrop => &self.closed_hand_no_drop,
CursorStyle::ArrowDown => &self.arrow_down,
CursorStyle::Draft => &self.draft,
CursorStyle::Fleur => &self.fleur,
CursorStyle::Help => &self.help,
CursorStyle::ArrowLeft => &self.arrow_left,
CursorStyle::SideLeft => &self.side_left,
CursorStyle::NoDrop => &self.no_drop,
CursorStyle::NotAllowed => &self.not_allowed,
CursorStyle::HandOpen => &self.open_hand,
CursorStyle::Pencil => &self.pencil,
CursorStyle::Pirate => &self.pirate,
CursorStyle::Pointer => &self.pointer,
CursorStyle::ArrowRight => &self.arrow_right,
CursorStyle::MirroredPointer => &self.mirrored_pointer,
CursorStyle::SideRight => &self.side_right,
CursorStyle::ResizeNESW => &self.size_nesw,
CursorStyle::ResizeNWSE => &self.size_nwse,
CursorStyle::SizeHor => &self.size_hor,
CursorStyle::ResizeVertically => &self.size_ver,
CursorStyle::Text => &self.text,
CursorStyle::ArrowTopLeft => &self.arrow_top_left,
CursorStyle::ArrowTopRight => &self.arrow_top_right,
CursorStyle::SideTop => &self.side_top,
CursorStyle::ArrowUp => &self.arrow_up,
CursorStyle::VerticalText => &self.vertical_text,
CursorStyle::ZoomIn => &self.zoom_in,
CursorStyle::ZoomOut => &self.zoom_out,
}
}
}
#[cfg_attr(feature = "bitcode", derive(bitcode::Encode, bitcode::Decode))]
#[cfg_attr(
feature = "wincode",
derive(wincode::SchemaWrite, wincode::SchemaRead)
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub struct BaseCursor {
hot_spot_x: u16,
hot_spot_y: u16,
}
#[cfg(feature = "keycodes")]
pub fn use_cursor(
cursor: &Cursor,
#[cfg(all(feature = "glfw", not(target_arch = "wasm32")))]
glfw_window: Option<&mut glfw::Window>,
#[cfg(not(all(feature = "glfw", not(target_arch = "wasm32"))))]
_glfw_window: core::option::Option<()>,
) -> Result<(), WindowError> {
#[cfg(not(target_arch = "wasm32"))]
#[cfg(feature = "glfw")]
if let Some(additional_info) = glfw_window {
#[allow(irrefutable_let_patterns)]
if let Cursor::Glfw(new_cursor) = cursor {
use crate::graphics::buffer_to_pixel_image;
let given = new_cursor;
let buffer = &given.0;
let pixel: glfw::PixelImage = buffer_to_pixel_image(buffer);
if given.1 == 0 || given.2 == 0 || given.1 > 1024 || given.2 > 1024
{
return Err(WindowError::IncorrectSize(
(given.1, given.2).try_tuple_into().unwrap_or_default(),
));
}
let new = glfw::Cursor::create_from_pixels(pixel, given.1, given.2);
additional_info.set_cursor(Some(new));
} else {
use crate::platform::windowing::WindowError;
return Err(WindowError::Misc(format!(
"Cursor of type Cursor::Glfw expected but got {cursor:?} instead"
)));
}
#[allow(unreachable_code)]
return Ok(());
}
match cursor {
#[cfg(target_os = "windows")]
#[cfg(feature = "svg")]
#[cfg(feature = "system")]
Cursor::Win(cursor) => {
unsafe {
cursors_windows::update_cursor(cursor);
cursors_windows::set_cursor(cursor);
}
}
#[cfg(target_os = "linux")]
Cursor::X11(xcursor_id) => {
return Err(WindowError::NotImplemented);
}
#[cfg(target_os = "macos")]
Cursor::Mac(_ptr) => {
return Err(WindowError::NotImplemented);
}
Cursor::Glfw(_) => {
return Err(WindowError::Misc("Impossible".to_string()));
}
}
#[allow(unreachable_code)]
Ok(())
}
impl ButtonState {
#[must_use]
pub const fn new(current: bool, last: bool) -> Self {
Self {
down: current,
clicked: current && !last,
released: !current && last,
}
}
pub const fn update(&mut self, new: bool) {
self.clicked = !self.down && new;
self.released = self.down && !new;
self.down = new;
}
}
#[cfg_attr(feature = "bitcode", derive(bitcode::Encode, bitcode::Decode))]
#[cfg_attr(
feature = "wincode",
derive(wincode::SchemaWrite, wincode::SchemaRead)
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash, PartialOrd, Ord)]
#[allow(missing_docs, clippy::struct_excessive_bools)]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub struct ButtonState {
pub down: bool,
pub clicked: bool,
pub released: bool,
}
#[cfg_attr(feature = "bitcode", derive(bitcode::Encode, bitcode::Decode))]
#[cfg_attr(
feature = "wincode",
derive(wincode::SchemaWrite, wincode::SchemaRead)
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub struct MouseButtonState {
pub left: ButtonState,
pub middle: ButtonState,
pub right: ButtonState,
}
impl MouseButtonState {
#[must_use]
pub const fn new_default(
left_down: bool,
middle_down: bool,
right_down: bool,
) -> Self {
Self {
left: ButtonState::new(left_down, false),
middle: ButtonState::new(middle_down, false),
right: ButtonState::new(right_down, false),
}
}
#[must_use]
pub const fn new(
left_down: bool,
middle_down: bool,
right_down: bool,
previous_left_down: bool,
previous_middle_down: bool,
previous_right_down: bool,
) -> Self {
Self {
left: ButtonState::new(left_down, previous_left_down),
middle: ButtonState::new(middle_down, previous_middle_down),
right: ButtonState::new(right_down, previous_right_down),
}
}
pub const fn update(
&mut self,
left_down: bool,
middle_down: bool,
right_down: bool,
) {
self.left.update(left_down);
self.middle.update(middle_down);
self.right.update(right_down);
}
pub const fn update_with_snapshot(&mut self, snapshot: &MouseSnapShot) {
self.update(
snapshot.left_down,
snapshot.middle_down,
snapshot.right_down,
);
}
pub fn update_with_framework<
T: crate::platform::windowing::traits::MouseInput,
>(
&mut self,
framework: &T,
) {
self.update(
framework.is_mouse_down(crate::platform::MouseButton::Left),
framework.is_mouse_down(crate::platform::MouseButton::Middle),
framework.is_mouse_down(crate::platform::MouseButton::Right),
);
}
}
#[cfg_attr(feature = "bitcode", derive(bitcode::Encode, bitcode::Decode))]
#[cfg_attr(
feature = "wincode",
derive(wincode::SchemaWrite, wincode::SchemaRead)
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Default, PartialOrd)]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub struct MouseSnapShot {
pub position: Option<(f32, f32)>,
pub scroll: (f32, f32),
pub left_down: bool,
pub middle_down: bool,
pub right_down: bool,
}
impl MouseSnapShot {
#[must_use]
pub const fn to_mouse_button_state(
&self,
previous_left: bool,
previous_middle: bool,
previous_right: bool,
) -> MouseButtonState {
MouseButtonState::new(
self.left_down,
self.middle_down,
self.right_down,
previous_left,
previous_middle,
previous_right,
)
}
}
impl MouseSnapShot {
#[must_use]
pub const fn set_position(mut self, position: Option<(f32, f32)>) -> Self {
self.position = position;
self
}
#[must_use]
pub const fn set_scroll(mut self, scroll: (f32, f32)) -> Self {
self.scroll = scroll;
self
}
#[must_use]
pub const fn set_left_down(mut self, left_down: bool) -> Self {
self.left_down = left_down;
self
}
#[must_use]
pub const fn set_middle_down(mut self, middle_down: bool) -> Self {
self.middle_down = middle_down;
self
}
#[must_use]
pub const fn set_right_down(mut self, right_down: bool) -> Self {
self.right_down = right_down;
self
}
}
#[cfg_attr(all(feature = "strum"), derive(strum::EnumIter))]
#[cfg_attr(feature = "bitcode", derive(bitcode::Encode, bitcode::Decode))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub enum LoadCursorError {
InvalidImageData(String),
Misc(String),
UnableToCreateTempfile,
UnableToDeleteTempfile,
OsError,
InvalidHotspot,
}
#[cfg_attr(all(feature = "strum"), derive(strum::EnumIter))]
#[cfg_attr(all(feature = "enum_ext"), enum_ext::enum_extend)]
#[cfg_attr(feature = "bitcode", derive(bitcode::Encode, bitcode::Decode))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub enum CursorResolution {
X16,
X32,
X64,
X128,
X256,
}
impl CursorResolution {
#[must_use]
pub fn get_size<T>(&self) -> T
where
u8: IntoPatch<T>,
{
match self {
Self::X16 => 15,
Self::X32 => 31,
Self::X64 => 63,
Self::X128 => 127,
Self::X256 => 255,
}
.into_value()
}
#[must_use]
pub fn try_get_size<T>(&self) -> Option<T>
where
u8: TryIntoPatch<T>,
{
match self {
Self::X16 => 15,
Self::X32 => 31,
Self::X64 => 63,
Self::X128 => 127,
Self::X256 => 255,
}
.try_into_value()
}
}