1use std::{
2 any::TypeId,
3 cell::{Cell, RefCell},
4 collections::{HashMap, VecDeque},
5 fmt,
6 future::Future,
7 hash::{Hash, Hasher},
8 pin::Pin,
9 rc::Rc,
10 sync::Arc,
11 task::{Context, Poll, Waker},
12};
13
14use cranpose_core::hash::default;
15use cranpose_foundation::{
16 DelegatableNode, ModifierNode, ModifierNodeContext, ModifierNodeElement, NodeCapabilities,
17 NodeState, PointerInputNode, impl_pointer_input_node,
18};
19use cranpose_ui_graphics::Size;
20use futures_task::{ArcWake, waker};
21
22use super::{Modifier, PointerEvent, inspector_metadata};
23
24impl Modifier {
25 #[track_caller]
36 pub fn pointer_input<K, F, Fut>(self, key: K, handler: F) -> Self
37 where
38 K: Hash + 'static,
39 F: Fn(PointerInputScope) -> Fut + 'static,
40 Fut: Future<Output = ()> + 'static,
41 {
42 let element = PointerInputElement::new(
43 KeyToken::declaration_site(std::panic::Location::caller()),
44 vec![KeyToken::new(&key)],
45 pointer_input_handler(handler),
46 );
47 let key_count = element.key_count();
48 let handler_id = element.handler_id();
49 self.then(
50 Self::with_element(element).with_inspector_metadata(inspector_metadata(
51 "pointerInput",
52 move |info| {
53 info.add_property("keyCount", key_count.to_string());
54 info.add_property("handlerId", handler_id.to_string());
55 },
56 )),
57 )
58 }
59}
60
61fn pointer_input_handler<F, Fut>(handler: F) -> PointerInputHandler
62where
63 F: Fn(PointerInputScope) -> Fut + 'static,
64 Fut: Future<Output = ()> + 'static,
65{
66 Rc::new(move |scope| Box::pin(handler(scope.clone())))
67}
68
69type PointerInputFuture = Pin<Box<dyn Future<Output = ()>>>;
70type PointerInputHandler = Rc<dyn Fn(PointerInputScope) -> PointerInputFuture>;
71
72#[derive(Clone, Copy, Debug, PartialEq, Eq)]
73pub(crate) enum PointerInputTaskOwner {
74 App(crate::render_state::AppContextId),
75}
76
77pub(crate) struct PointerInputTaskRegistry {
78 tasks: RefCell<HashMap<u64, Rc<PointerInputTaskInner>>>,
79}
80
81impl PointerInputTaskRegistry {
82 pub(crate) fn new() -> Self {
83 Self {
84 tasks: RefCell::new(HashMap::new()),
85 }
86 }
87
88 pub(crate) fn insert(&self, task_id: u64, task: Rc<PointerInputTaskInner>) {
89 self.tasks.borrow_mut().insert(task_id, task);
90 }
91
92 pub(crate) fn remove(&self, task_id: u64) {
93 self.tasks.borrow_mut().remove(&task_id);
94 }
95
96 pub(crate) fn request_poll(&self, task_id: u64, owner: PointerInputTaskOwner) {
97 if let Some(task) = self.tasks.borrow().get(&task_id).cloned() {
98 task.request_poll(owner, task_id);
99 }
100 }
101}
102
103#[derive(Clone)]
104struct PointerInputElement {
105 site: KeyToken,
106 keys: Vec<KeyToken>,
107 handler: PointerInputHandler,
108 handler_id: u64,
109}
110
111impl PointerInputElement {
112 fn new(site: KeyToken, keys: Vec<KeyToken>, handler: PointerInputHandler) -> Self {
113 let handler_id = pointer_handler_identity(&handler);
114 Self {
115 site,
116 keys,
117 handler,
118 handler_id,
119 }
120 }
121
122 fn key_count(&self) -> usize {
123 self.keys.len()
124 }
125
126 fn handler_id(&self) -> u64 {
127 self.handler_id
128 }
129}
130
131fn pointer_handler_identity(handler: &PointerInputHandler) -> u64 {
132 Rc::as_ptr(handler) as *const () as usize as u64
133}
134
135impl fmt::Debug for PointerInputElement {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 f.debug_struct("PointerInputElement")
138 .field("site", &self.site)
139 .field("keys", &self.keys)
140 .field("handler", &Rc::as_ptr(&self.handler))
141 .field("handler_id", &self.handler_id)
142 .finish()
143 }
144}
145
146impl PartialEq for PointerInputElement {
147 fn eq(&self, other: &Self) -> bool {
148 self.site == other.site && self.keys == other.keys
149 }
150}
151
152impl Eq for PointerInputElement {}
153
154impl Hash for PointerInputElement {
155 fn hash<H: Hasher>(&self, state: &mut H) {
156 self.site.hash(state);
157 self.keys.hash(state);
158 }
159}
160
161impl ModifierNodeElement for PointerInputElement {
162 type Node = SuspendingPointerInputNode;
163
164 fn create(&self) -> Self::Node {
165 SuspendingPointerInputNode::new(self.site, self.keys.clone(), self.handler.clone())
166 }
167
168 fn update(&self, node: &mut Self::Node) {
169 node.update(self.site, self.keys.clone(), self.handler.clone());
170 }
171
172 fn capabilities(&self) -> NodeCapabilities {
173 NodeCapabilities::POINTER_INPUT
174 }
175}
176
177#[derive(Clone)]
178pub struct PointerInputScope {
179 state: Rc<PointerInputScopeState>,
180}
181
182impl PointerInputScope {
183 fn new(state: Rc<PointerInputScopeState>) -> Self {
184 Self { state }
185 }
186
187 pub fn size(&self) -> Size {
196 self.state.size.get()
197 }
198
199 pub async fn await_pointer_event_scope<R, F, Fut>(&self, block: F) -> R
200 where
201 F: FnOnce(AwaitPointerEventScope) -> Fut,
202 Fut: Future<Output = R>,
203 {
204 let scope = AwaitPointerEventScope {
205 state: self.state.clone(),
206 };
207 block(scope).await
208 }
209}
210
211#[derive(Clone)]
212pub struct AwaitPointerEventScope {
213 state: Rc<PointerInputScopeState>,
214}
215
216impl AwaitPointerEventScope {
217 pub fn size(&self) -> Size {
220 self.state.size.get()
221 }
222
223 pub async fn await_pointer_event(&self) -> PointerEvent {
224 NextPointerEvent {
225 state: self.state.clone(),
226 }
227 .await
228 }
229}
230
231struct NextPointerEvent {
232 state: Rc<PointerInputScopeState>,
233}
234
235impl Future for NextPointerEvent {
236 type Output = PointerEvent;
237
238 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
239 self.state.poll_event(cx)
240 }
241}
242
243struct PointerInputScopeState {
244 events: RefCell<VecDeque<PointerEvent>>,
245 waiting: RefCell<Option<Waker>>,
246 size: Rc<Cell<Size>>,
247}
248
249impl PointerInputScopeState {
250 fn new(size: Rc<Cell<Size>>) -> Self {
251 Self {
252 events: RefCell::new(VecDeque::new()),
253 waiting: RefCell::new(None),
254 size,
255 }
256 }
257
258 fn push_event(&self, event: PointerEvent) {
259 self.events.borrow_mut().push_back(event);
260 let waker = {
261 let mut waiting = self.waiting.borrow_mut();
262 waiting.take()
263 };
264 if let Some(waker) = waker {
265 waker.wake();
266 }
267 }
268
269 fn poll_event(&self, cx: &mut Context<'_>) -> Poll<PointerEvent> {
270 if let Some(event) = self.events.borrow_mut().pop_front() {
271 Poll::Ready(event)
272 } else {
273 self.waiting.replace(Some(cx.waker().clone()));
274 Poll::Pending
275 }
276 }
277}
278
279struct PointerEventDispatcher {
280 state: Rc<RefCell<Option<Rc<PointerInputScopeState>>>>,
281 handler: Rc<dyn Fn(PointerEvent)>,
282}
283
284impl PointerEventDispatcher {
285 fn new() -> Self {
286 let state = Rc::new(RefCell::new(None::<Rc<PointerInputScopeState>>));
287 let state_for_handler = state.clone();
288 let handler = Rc::new(move |event: PointerEvent| {
289 if let Some(inner) = state_for_handler.borrow().as_ref() {
290 inner.push_event(event);
291 }
292 });
293 Self { state, handler }
294 }
295
296 fn handler(&self) -> Rc<dyn Fn(PointerEvent)> {
297 self.handler.clone()
298 }
299
300 fn set_state(&self, state: Option<Rc<PointerInputScopeState>>) {
301 *self.state.borrow_mut() = state;
302 }
303}
304
305struct PointerInputTask {
306 id: u64,
307 owner: PointerInputTaskOwner,
308 inner: Rc<PointerInputTaskInner>,
309}
310
311impl PointerInputTask {
312 fn new(future: PointerInputFuture) -> Self {
313 let inner = Rc::new(PointerInputTaskInner::new(future));
314 let id = Rc::as_ptr(&inner) as usize as u64;
315 let owner = crate::render_state::register_pointer_input_task(id, inner.clone());
316 Self { id, owner, inner }
317 }
318
319 fn poll(&self) {
320 self.inner.poll(self.owner, self.id);
321 }
322
323 fn cancel(self) {
324 self.inner.cancel();
325 crate::render_state::remove_pointer_input_task(self.owner, self.id);
326 }
327}
328
329impl Drop for PointerInputTask {
330 fn drop(&mut self) {
331 self.inner.cancel();
332 crate::render_state::remove_pointer_input_task(self.owner, self.id);
333 }
334}
335
336pub(crate) struct PointerInputTaskInner {
337 future: RefCell<Option<PointerInputFuture>>,
338 is_polling: Cell<bool>,
339 needs_poll: Cell<bool>,
340}
341
342impl PointerInputTaskInner {
343 fn new(future: PointerInputFuture) -> Self {
344 Self {
345 future: RefCell::new(Some(future)),
346 is_polling: Cell::new(false),
347 needs_poll: Cell::new(false),
348 }
349 }
350
351 fn cancel(&self) {
352 self.future.borrow_mut().take();
353 }
354
355 fn request_poll(&self, owner: PointerInputTaskOwner, task_id: u64) {
356 if self.is_polling.get() {
357 self.needs_poll.set(true);
358 } else {
359 self.poll(owner, task_id);
360 }
361 }
362
363 fn poll(&self, owner: PointerInputTaskOwner, task_id: u64) {
364 if self.is_polling.replace(true) {
365 self.needs_poll.set(true);
366 return;
367 }
368 loop {
369 self.needs_poll.set(false);
370 let waker = waker(Arc::new(PointerInputTaskWaker { task_id, owner }));
371 let mut cx = Context::from_waker(&waker);
372 let mut future_slot = self.future.borrow_mut();
373 if let Some(future) = future_slot.as_mut() {
374 let poll_result = future.as_mut().poll(&mut cx);
375 if poll_result.is_ready() {
376 future_slot.take();
377 }
378 }
379 if !self.needs_poll.get() {
380 break;
381 }
382 }
383 self.is_polling.set(false);
384 }
385}
386
387struct PointerInputTaskWaker {
388 task_id: u64,
389 owner: PointerInputTaskOwner,
390}
391
392impl ArcWake for PointerInputTaskWaker {
393 fn wake_by_ref(arc_self: &Arc<Self>) {
394 crate::render_state::request_pointer_input_task_poll(arc_self.owner, arc_self.task_id);
395 }
396}
397
398pub struct SuspendingPointerInputNode {
399 site: KeyToken,
400 keys: Vec<KeyToken>,
401 handler: PointerInputHandler,
402 dispatcher: PointerEventDispatcher,
403 task: Option<PointerInputTask>,
404 layout_size: Rc<Cell<Size>>,
405 state: NodeState,
406}
407
408impl SuspendingPointerInputNode {
409 fn new(site: KeyToken, keys: Vec<KeyToken>, handler: PointerInputHandler) -> Self {
410 Self {
411 site,
412 keys,
413 handler,
414 dispatcher: PointerEventDispatcher::new(),
415 task: None,
416 layout_size: Rc::new(Cell::new(Size {
417 width: 0.0,
418 height: 0.0,
419 })),
420 state: NodeState::new(),
421 }
422 }
423
424 fn update(&mut self, site: KeyToken, keys: Vec<KeyToken>, handler: PointerInputHandler) {
425 let should_restart = self.site != site || self.keys != keys;
426 self.site = site;
427 self.keys = keys;
428 self.handler = handler;
429 if should_restart {
430 self.restart();
431 }
432 }
433
434 fn restart(&mut self) {
435 self.cancel();
436 self.start();
437 }
438
439 fn start(&mut self) {
440 let state = Rc::new(PointerInputScopeState::new(self.layout_size.clone()));
441 self.dispatcher.set_state(Some(state.clone()));
442 let scope = PointerInputScope::new(state);
443 let future = (self.handler)(scope);
444 let task = PointerInputTask::new(future);
445 task.poll();
446 self.task = Some(task);
447 }
448
449 fn cancel(&mut self) {
450 if let Some(task) = self.task.take() {
451 task.cancel();
452 }
453 self.dispatcher.set_state(None);
454 }
455}
456
457impl Drop for SuspendingPointerInputNode {
458 fn drop(&mut self) {
459 self.cancel();
460 }
461}
462
463impl ModifierNode for SuspendingPointerInputNode {
464 fn on_attach(&mut self, _context: &mut dyn ModifierNodeContext) {
465 self.start();
466 }
467
468 fn on_detach(&mut self) {
469 self.cancel();
470 }
471
472 fn on_reset(&mut self) {}
473
474 impl_pointer_input_node!();
475}
476
477impl DelegatableNode for SuspendingPointerInputNode {
478 fn node_state(&self) -> &NodeState {
479 &self.state
480 }
481}
482
483impl PointerInputNode for SuspendingPointerInputNode {
484 fn pointer_input_handler(&self) -> Option<Rc<dyn Fn(PointerEvent)>> {
485 Some(self.dispatcher.handler())
486 }
487
488 fn layout_size_sink(&self) -> Option<Rc<Cell<Size>>> {
489 Some(self.layout_size.clone())
490 }
491}
492
493#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
494struct KeyToken {
495 type_id: TypeId,
496 hash: u64,
497}
498
499impl KeyToken {
500 fn declaration_site(site: &'static std::panic::Location<'static>) -> Self {
501 Self::new(&(site.file(), site.line(), site.column()))
502 }
503
504 fn new<T: Hash + 'static>(value: &T) -> Self {
505 let mut hasher = default::new();
506 value.hash(&mut hasher);
507 Self {
508 type_id: TypeId::of::<T>(),
509 hash: hasher.finish(),
510 }
511 }
512}