Allow custom cursor caching (#3276)

This commit is contained in:
daxpedda 2023-12-22 22:20:41 +01:00 committed by GitHub
parent 0a7ea61834
commit 2c15de7cf9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 579 additions and 347 deletions

View file

@ -1,7 +1,10 @@
use core::fmt;
use std::{error::Error, sync::Arc};
use std::hash::Hasher;
use std::sync::Arc;
use std::{error::Error, hash::Hash};
use crate::platform_impl::PlatformCustomCursor;
use crate::event_loop::EventLoopWindowTarget;
use crate::platform_impl::{self, PlatformCustomCursor, PlatformCustomCursorBuilder};
/// The maximum width and height for a cursor when using [`CustomCursor::from_rgba`].
pub const MAX_CURSOR_SIZE: u16 = 2048;
@ -16,25 +19,52 @@ const PIXEL_SIZE: usize = 4;
///
/// # Example
///
/// ```
/// use winit::window::CustomCursor;
/// ```no_run
/// use winit::{
/// event::{Event, WindowEvent},
/// event_loop::{ControlFlow, EventLoop},
/// window::{CustomCursor, Window},
/// };
///
/// let mut event_loop = EventLoop::new().unwrap();
///
/// let w = 10;
/// let h = 10;
/// let rgba = vec![255; (w * h * 4) as usize];
/// let custom_cursor = CustomCursor::from_rgba(rgba, w, h, w / 2, h / 2).unwrap();
///
/// #[cfg(not(target_family = "wasm"))]
/// let builder = CustomCursor::from_rgba(rgba, w, h, w / 2, h / 2).unwrap();
///
/// #[cfg(target_family = "wasm")]
/// let custom_cursor_url = {
/// let builder = {
/// use winit::platform::web::CustomCursorExtWebSys;
/// CustomCursor::from_url("http://localhost:3000/cursor.png", 0, 0).unwrap()
/// CustomCursor::from_url(String::from("http://localhost:3000/cursor.png"), 0, 0)
/// };
///
/// let custom_cursor = builder.build(&event_loop);
///
/// let window = Window::new(&event_loop).unwrap();
/// window.set_custom_cursor(&custom_cursor);
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Clone, Debug)]
pub struct CustomCursor {
pub(crate) inner: Arc<PlatformCustomCursor>,
}
impl Hash for CustomCursor {
fn hash<H: Hasher>(&self, state: &mut H) {
Arc::as_ptr(&self.inner).hash(state);
}
}
impl PartialEq for CustomCursor {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.inner, &other.inner)
}
}
impl Eq for CustomCursor {}
impl CustomCursor {
/// Creates a new cursor from an rgba buffer.
///
@ -48,20 +78,35 @@ impl CustomCursor {
height: u16,
hotspot_x: u16,
hotspot_y: u16,
) -> Result<Self, BadImage> {
Ok(Self {
) -> Result<CustomCursorBuilder, BadImage> {
Ok(CustomCursorBuilder {
inner: PlatformCustomCursor::from_rgba(
rgba.into(),
width,
height,
hotspot_x,
hotspot_y,
)?
.into(),
)?,
})
}
}
/// Builds a [`CustomCursor`].
///
/// See [`CustomCursor`] for more details.
#[derive(Debug)]
pub struct CustomCursorBuilder {
pub(crate) inner: PlatformCustomCursorBuilder,
}
impl CustomCursorBuilder {
pub fn build<T>(self, window_target: &EventLoopWindowTarget<T>) -> CustomCursor {
CustomCursor {
inner: self.inner.build(&window_target.p),
}
}
}
/// An error produced when using [`CustomCursor::from_rgba`] with invalid arguments.
#[derive(Debug, Clone)]
pub enum BadImage {
@ -177,6 +222,10 @@ impl CursorImage {
hotspot_y,
})
}
fn build<T>(self, _: &platform_impl::EventLoopWindowTarget<T>) -> Arc<CursorImage> {
Arc::new(self)
}
}
// Platforms that don't support cursors will export this as `PlatformCustomCursor`.
@ -195,4 +244,8 @@ impl NoCustomCursor {
CursorImage::from_rgba(rgba, width, height, hotspot_x, hotspot_y)?;
Ok(Self)
}
fn build<T>(self, _: &platform_impl::EventLoopWindowTarget<T>) -> Arc<NoCustomCursor> {
Arc::new(self)
}
}