use crate::bitmap::Bitmap;
use crate::geometry::Point;
use std::ffi::CString;
use wxdragon_sys as ffi;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum StockCursor {
None,
Arrow,
RightArrow,
Bullseye,
Char,
Cross,
Hand,
IBeam,
LeftButton,
Magnifier,
MiddleButton,
NoEntry,
PaintBrush,
Pencil,
PointLeft,
PointRight,
QuestionArrow,
RightButton,
SizeNESW,
SizeNS,
SizeNWSE,
SizeWE,
Sizing,
SprayCan,
Wait,
Watch,
Blank,
Default,
ArrowWait,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum BitmapType {
Invalid,
Bmp,
Ico,
Cur,
Xbm,
Xpm,
Png,
Jpeg,
Gif,
Ani,
Any,
}
#[derive(Debug)]
pub struct Cursor(pub(crate) *mut ffi::wxd_Cursor_t);
impl Cursor {
pub fn from_stock(cursor_type: StockCursor) -> Option<Self> {
let ffi_cursor_type = match cursor_type {
StockCursor::None => ffi::wxd_StockCursor_WXD_CURSOR_NONE,
StockCursor::Arrow => ffi::wxd_StockCursor_WXD_CURSOR_ARROW,
StockCursor::RightArrow => ffi::wxd_StockCursor_WXD_CURSOR_RIGHT_ARROW,
StockCursor::Bullseye => ffi::wxd_StockCursor_WXD_CURSOR_BULLSEYE,
StockCursor::Char => ffi::wxd_StockCursor_WXD_CURSOR_CHAR,
StockCursor::Cross => ffi::wxd_StockCursor_WXD_CURSOR_CROSS,
StockCursor::Hand => ffi::wxd_StockCursor_WXD_CURSOR_HAND,
StockCursor::IBeam => ffi::wxd_StockCursor_WXD_CURSOR_IBEAM,
StockCursor::LeftButton => ffi::wxd_StockCursor_WXD_CURSOR_LEFT_BUTTON,
StockCursor::Magnifier => ffi::wxd_StockCursor_WXD_CURSOR_MAGNIFIER,
StockCursor::MiddleButton => ffi::wxd_StockCursor_WXD_CURSOR_MIDDLE_BUTTON,
StockCursor::NoEntry => ffi::wxd_StockCursor_WXD_CURSOR_NO_ENTRY,
StockCursor::PaintBrush => ffi::wxd_StockCursor_WXD_CURSOR_PAINT_BRUSH,
StockCursor::Pencil => ffi::wxd_StockCursor_WXD_CURSOR_PENCIL,
StockCursor::PointLeft => ffi::wxd_StockCursor_WXD_CURSOR_POINT_LEFT,
StockCursor::PointRight => ffi::wxd_StockCursor_WXD_CURSOR_POINT_RIGHT,
StockCursor::QuestionArrow => ffi::wxd_StockCursor_WXD_CURSOR_QUESTION_ARROW,
StockCursor::RightButton => ffi::wxd_StockCursor_WXD_CURSOR_RIGHT_BUTTON,
StockCursor::SizeNESW => ffi::wxd_StockCursor_WXD_CURSOR_SIZENESW,
StockCursor::SizeNS => ffi::wxd_StockCursor_WXD_CURSOR_SIZENS,
StockCursor::SizeNWSE => ffi::wxd_StockCursor_WXD_CURSOR_SIZENWSE,
StockCursor::SizeWE => ffi::wxd_StockCursor_WXD_CURSOR_SIZEWE,
StockCursor::Sizing => ffi::wxd_StockCursor_WXD_CURSOR_SIZING,
StockCursor::SprayCan => ffi::wxd_StockCursor_WXD_CURSOR_SPRAYCAN,
StockCursor::Wait => ffi::wxd_StockCursor_WXD_CURSOR_WAIT,
StockCursor::Watch => ffi::wxd_StockCursor_WXD_CURSOR_WATCH,
StockCursor::Blank => ffi::wxd_StockCursor_WXD_CURSOR_BLANK,
StockCursor::Default => ffi::wxd_StockCursor_WXD_CURSOR_DEFAULT,
StockCursor::ArrowWait => ffi::wxd_StockCursor_WXD_CURSOR_ARROWWAIT,
};
let ptr = unsafe { ffi::wxd_Cursor_CreateStock(ffi_cursor_type) };
if ptr.is_null() { None } else { Some(Self(ptr)) }
}
pub fn from_file(filename: &str, bitmap_type: BitmapType, hotspot_x: i32, hotspot_y: i32) -> Option<Self> {
let c_filename = CString::new(filename).ok()?;
let ptr = {
let ffi_bitmap_type = match bitmap_type {
BitmapType::Invalid => ffi::wxd_BitmapType_WXD_BITMAP_TYPE_INVALID,
BitmapType::Bmp => ffi::wxd_BitmapType_WXD_BITMAP_TYPE_BMP,
BitmapType::Ico => ffi::wxd_BitmapType_WXD_BITMAP_TYPE_ICO,
BitmapType::Cur => ffi::wxd_BitmapType_WXD_BITMAP_TYPE_CUR,
BitmapType::Xbm => ffi::wxd_BitmapType_WXD_BITMAP_TYPE_XBM,
BitmapType::Xpm => ffi::wxd_BitmapType_WXD_BITMAP_TYPE_XPM,
BitmapType::Png => ffi::wxd_BitmapType_WXD_BITMAP_TYPE_PNG,
BitmapType::Jpeg => ffi::wxd_BitmapType_WXD_BITMAP_TYPE_JPEG,
BitmapType::Gif => ffi::wxd_BitmapType_WXD_BITMAP_TYPE_GIF,
BitmapType::Ani => ffi::wxd_BitmapType_WXD_BITMAP_TYPE_ANI,
BitmapType::Any => ffi::wxd_BitmapType_WXD_BITMAP_TYPE_ANY,
};
unsafe { ffi::wxd_Cursor_CreateFromFile(c_filename.as_ptr(), ffi_bitmap_type, hotspot_x, hotspot_y) }
};
if ptr.is_null() { None } else { Some(Self(ptr)) }
}
pub fn from_data(
bits: &[u8],
width: i32,
height: i32,
hotspot_x: i32,
hotspot_y: i32,
mask_bits: Option<&[u8]>,
) -> Option<Self> {
if width <= 0 || height <= 0 {
return None;
}
let expected_size = ((width * height + 7) / 8) as usize;
if bits.len() < expected_size {
return None;
}
if let Some(mask) = mask_bits
&& mask.len() < expected_size
{
return None;
}
let mask_ptr = mask_bits.map(|m| m.as_ptr()).unwrap_or(std::ptr::null());
let ptr = unsafe { ffi::wxd_Cursor_CreateFromData(bits.as_ptr(), width, height, hotspot_x, hotspot_y, mask_ptr) };
if ptr.is_null() { None } else { Some(Self(ptr)) }
}
pub fn from_bitmap(bitmap: &Bitmap) -> Option<Self> {
let ptr = unsafe { ffi::wxd_Cursor_CreateFromImage(bitmap.as_const_ptr()) };
if ptr.is_null() { None } else { Some(Self(ptr)) }
}
pub fn copy(&self) -> Option<Self> {
let ptr = unsafe { ffi::wxd_Cursor_Copy(self.0) };
if ptr.is_null() { None } else { Some(Self(ptr)) }
}
pub fn is_ok(&self) -> bool {
unsafe { ffi::wxd_Cursor_IsOk(self.0) }
}
pub fn get_hotspot(&self) -> Point {
let point = unsafe { ffi::wxd_Cursor_GetHotSpot(self.0) };
Point::new(point.x, point.y)
}
pub unsafe fn get_handle(&self) -> *mut std::ffi::c_void {
unsafe { ffi::wxd_Cursor_GetHandle(self.0) }
}
pub unsafe fn set_handle(&self, handle: *mut std::ffi::c_void) {
unsafe { ffi::wxd_Cursor_SetHandle(self.0, handle) };
}
pub(crate) fn as_ptr(&self) -> *mut ffi::wxd_Cursor_t {
self.0
}
pub(crate) unsafe fn from_ptr(ptr: *mut ffi::wxd_Cursor_t) -> Option<Self> {
if ptr.is_null() { None } else { Some(Self(ptr)) }
}
pub fn is_null(&self) -> bool {
self.0.is_null()
}
}
impl Drop for Cursor {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe {
ffi::wxd_Cursor_Destroy(self.0);
}
}
}
}
unsafe impl Send for Cursor {}
unsafe impl Sync for Cursor {}
pub fn set_cursor(cursor: Option<&Cursor>) {
let cursor_ptr = cursor.map(|c| c.as_ptr()).unwrap_or(std::ptr::null_mut());
unsafe {
ffi::wxd_SetCursor(cursor_ptr);
}
}
pub fn begin_busy_cursor(cursor: Option<&Cursor>) {
let cursor_ptr = cursor.map(|c| c.as_ptr()).unwrap_or(std::ptr::null_mut());
unsafe {
ffi::wxd_BeginBusyCursor(cursor_ptr);
}
}
pub fn end_busy_cursor() {
unsafe {
ffi::wxd_EndBusyCursor();
}
}
pub fn is_busy() -> bool {
unsafe { ffi::wxd_IsBusy() }
}
pub struct BusyCursor {
_marker: (),
}
impl BusyCursor {
pub fn new(cursor: Option<&Cursor>) -> Self {
begin_busy_cursor(cursor);
Self { _marker: () }
}
}
impl Drop for BusyCursor {
fn drop(&mut self) {
end_busy_cursor();
}
}