Custom cursor improvements (#3292)
This commit is contained in:
parent
37946e0a3a
commit
e5310ade08
18 changed files with 152 additions and 101 deletions
|
|
@ -1,6 +1,8 @@
|
|||
use std::{
|
||||
cell::RefCell,
|
||||
future, mem,
|
||||
future,
|
||||
hash::{Hash, Hasher},
|
||||
mem,
|
||||
ops::DerefMut,
|
||||
rc::{self, Rc},
|
||||
sync::{self, Arc},
|
||||
|
|
@ -25,7 +27,7 @@ use self::thread_safe::ThreadSafe;
|
|||
use super::{backend::Style, r#async::AsyncSender, EventLoopWindowTarget};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CustomCursorBuilder {
|
||||
pub(crate) enum CustomCursorBuilder {
|
||||
Image(CursorImage),
|
||||
Url {
|
||||
url: String,
|
||||
|
|
@ -35,35 +37,6 @@ pub enum CustomCursorBuilder {
|
|||
}
|
||||
|
||||
impl CustomCursorBuilder {
|
||||
pub fn build<T>(self, window_target: &EventLoopWindowTarget<T>) -> Arc<CustomCursor> {
|
||||
Lazy::force(&DROP_HANDLER);
|
||||
|
||||
match self {
|
||||
Self::Image(image) => ImageState::from_rgba(
|
||||
window_target.runner.window(),
|
||||
window_target.runner.document().clone(),
|
||||
&image,
|
||||
),
|
||||
Self::Url {
|
||||
url,
|
||||
hotspot_x,
|
||||
hotspot_y,
|
||||
} => ImageState::from_url(url, hotspot_x, hotspot_y),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CustomCursor(Option<ThreadSafe<RefCell<ImageState>>>);
|
||||
|
||||
static DROP_HANDLER: Lazy<AsyncSender<ThreadSafe<RefCell<ImageState>>>> = Lazy::new(|| {
|
||||
let (sender, receiver) = r#async::channel();
|
||||
wasm_bindgen_futures::spawn_local(async move { while receiver.next().await.is_ok() {} });
|
||||
|
||||
sender
|
||||
});
|
||||
|
||||
impl CustomCursor {
|
||||
pub fn from_rgba(
|
||||
rgba: Vec<u8>,
|
||||
width: u16,
|
||||
|
|
@ -75,9 +48,60 @@ impl CustomCursor {
|
|||
rgba, width, height, hotspot_x, hotspot_y,
|
||||
)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CustomCursor(Arc<Inner>);
|
||||
|
||||
impl Hash for CustomCursor {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
Arc::as_ptr(&self.0).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for CustomCursor {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Arc::ptr_eq(&self.0, &other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for CustomCursor {}
|
||||
|
||||
impl CustomCursor {
|
||||
pub(crate) fn build<T>(
|
||||
builder: CustomCursorBuilder,
|
||||
window_target: &EventLoopWindowTarget<T>,
|
||||
) -> Self {
|
||||
Lazy::force(&DROP_HANDLER);
|
||||
|
||||
Self(match builder {
|
||||
CustomCursorBuilder::Image(image) => ImageState::from_rgba(
|
||||
window_target.runner.window(),
|
||||
window_target.runner.document().clone(),
|
||||
&image,
|
||||
),
|
||||
CustomCursorBuilder::Url {
|
||||
url,
|
||||
hotspot_x,
|
||||
hotspot_y,
|
||||
} => ImageState::from_url(url, hotspot_x, hotspot_y),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Inner(Option<ThreadSafe<RefCell<ImageState>>>);
|
||||
|
||||
static DROP_HANDLER: Lazy<AsyncSender<ThreadSafe<RefCell<ImageState>>>> = Lazy::new(|| {
|
||||
let (sender, receiver) = r#async::channel();
|
||||
wasm_bindgen_futures::spawn_local(async move { while receiver.next().await.is_ok() {} });
|
||||
|
||||
sender
|
||||
});
|
||||
|
||||
impl Inner {
|
||||
fn new() -> Arc<Self> {
|
||||
Arc::new(Self(Some(ThreadSafe::new(RefCell::new(
|
||||
Arc::new(Inner(Some(ThreadSafe::new(RefCell::new(
|
||||
ImageState::Loading(None),
|
||||
)))))
|
||||
}
|
||||
|
|
@ -90,7 +114,7 @@ impl CustomCursor {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drop for CustomCursor {
|
||||
impl Drop for Inner {
|
||||
fn drop(&mut self) {
|
||||
let value = self
|
||||
.0
|
||||
|
|
@ -130,13 +154,13 @@ impl CursorState {
|
|||
this.set_style();
|
||||
}
|
||||
|
||||
pub fn set_custom_cursor(&self, cursor: Arc<CustomCursor>) {
|
||||
pub(crate) fn set_custom_cursor(&self, cursor: CustomCursor) {
|
||||
let mut this = self.0.borrow_mut();
|
||||
|
||||
match cursor.get().borrow_mut().deref_mut() {
|
||||
match cursor.0.get().borrow_mut().deref_mut() {
|
||||
ImageState::Loading(state) => {
|
||||
this.cursor = SelectedCursor::ImageLoading {
|
||||
state: cursor.clone(),
|
||||
state: cursor.0.clone(),
|
||||
previous: mem::take(&mut this.cursor).into(),
|
||||
};
|
||||
*state = Some(Rc::downgrade(&self.0));
|
||||
|
|
@ -187,7 +211,7 @@ impl State {
|
|||
enum SelectedCursor {
|
||||
Named(CursorIcon),
|
||||
ImageLoading {
|
||||
state: Arc<CustomCursor>,
|
||||
state: Arc<Inner>,
|
||||
previous: Previous,
|
||||
},
|
||||
ImageReady(Rc<Image>),
|
||||
|
|
@ -241,7 +265,7 @@ enum ImageState {
|
|||
}
|
||||
|
||||
impl ImageState {
|
||||
fn from_rgba(window: &Window, document: Document, image: &CursorImage) -> Arc<CustomCursor> {
|
||||
fn from_rgba(window: &Window, document: Document, image: &CursorImage) -> Arc<Inner> {
|
||||
// 1. Create an `ImageData` from the RGBA data.
|
||||
// 2. Create an `ImageBitmap` from the `ImageData`.
|
||||
// 3. Draw `ImageBitmap` on an `HTMLCanvasElement`.
|
||||
|
|
@ -293,7 +317,7 @@ impl ImageState {
|
|||
.expect("unexpected exception in `createImageBitmap()`"),
|
||||
);
|
||||
|
||||
let this = CustomCursor::new();
|
||||
let this = Inner::new();
|
||||
|
||||
wasm_bindgen_futures::spawn_local({
|
||||
let weak = Arc::downgrade(&this);
|
||||
|
|
@ -406,8 +430,8 @@ impl ImageState {
|
|||
this
|
||||
}
|
||||
|
||||
fn from_url(url: String, hotspot_x: u16, hotspot_y: u16) -> Arc<CustomCursor> {
|
||||
let this = CustomCursor::new();
|
||||
fn from_url(url: String, hotspot_x: u16, hotspot_y: u16) -> Arc<Inner> {
|
||||
let this = Inner::new();
|
||||
wasm_bindgen_futures::spawn_local(Self::decode(
|
||||
Arc::downgrade(&this),
|
||||
url,
|
||||
|
|
@ -420,7 +444,7 @@ impl ImageState {
|
|||
}
|
||||
|
||||
async fn decode(
|
||||
weak: sync::Weak<CustomCursor>,
|
||||
weak: sync::Weak<Inner>,
|
||||
url: String,
|
||||
object: bool,
|
||||
hotspot_x: u16,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ use web_sys::HtmlCanvasElement;
|
|||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct Window {
|
||||
inner: Dispatcher<Inner>,
|
||||
|
|
@ -218,7 +217,7 @@ impl Inner {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn set_custom_cursor(&self, cursor: Arc<PlatformCustomCursor>) {
|
||||
pub(crate) fn set_custom_cursor(&self, cursor: PlatformCustomCursor) {
|
||||
self.cursor.set_custom_cursor(cursor)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue