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 impl_pointer_input_node, DelegatableNode, ModifierNode, ModifierNodeContext,
17 ModifierNodeElement, NodeCapabilities, NodeState, PointerInputNode,
18};
19use cranpose_ui_graphics::Size;
20use futures_task::{waker, ArcWake};
21
22use super::{inspector_metadata, Modifier, PointerEvent};
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,
108 keys: Vec<KeyToken>,
109 handler: PointerInputHandler,
110 handler_id: u64,
111}
112
113impl PointerInputElement {
114 fn new(site: KeyToken, keys: Vec<KeyToken>, handler: PointerInputHandler) -> Self {
115 let handler_id = pointer_handler_identity(&handler);
116 Self {
117 site,
118 keys,
119 handler,
120 handler_id,
121 }
122 }
123
124 fn key_count(&self) -> usize {
125 self.keys.len()
126 }
127
128 fn handler_id(&self) -> u64 {
129 self.handler_id
130 }
131}
132
133fn pointer_handler_identity(handler: &PointerInputHandler) -> u64 {
134 Rc::as_ptr(handler) as *const () as usize as u64
135}
136
137impl fmt::Debug for PointerInputElement {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 f.debug_struct("PointerInputElement")
140 .field("site", &self.site)
141 .field("keys", &self.keys)
142 .field("handler", &Rc::as_ptr(&self.handler))
143 .field("handler_id", &self.handler_id)
144 .finish()
145 }
146}
147
148impl PartialEq for PointerInputElement {
149 fn eq(&self, other: &Self) -> bool {
150 self.site == other.site && self.keys == other.keys
154 }
155}
156
157impl Eq for PointerInputElement {}
158
159impl Hash for PointerInputElement {
160 fn hash<H: Hasher>(&self, state: &mut H) {
161 self.site.hash(state);
164 self.keys.hash(state);
165 }
166}
167
168impl ModifierNodeElement for PointerInputElement {
169 type Node = SuspendingPointerInputNode;
170
171 fn create(&self) -> Self::Node {
172 SuspendingPointerInputNode::new(self.site, self.keys.clone(), self.handler.clone())
173 }
174
175 fn update(&self, node: &mut Self::Node) {
176 node.update(self.site, self.keys.clone(), self.handler.clone());
177 }
178
179 fn capabilities(&self) -> NodeCapabilities {
180 NodeCapabilities::POINTER_INPUT
181 }
182}
183
184#[derive(Clone)]
185pub struct PointerInputScope {
186 state: Rc<PointerInputScopeState>,
187}
188
189impl PointerInputScope {
190 fn new(state: Rc<PointerInputScopeState>) -> Self {
191 Self { state }
192 }
193
194 pub fn size(&self) -> Size {
203 self.state.size.get()
204 }
205
206 pub async fn await_pointer_event_scope<R, F, Fut>(&self, block: F) -> R
207 where
208 F: FnOnce(AwaitPointerEventScope) -> Fut,
209 Fut: Future<Output = R>,
210 {
211 let scope = AwaitPointerEventScope {
212 state: self.state.clone(),
213 };
214 block(scope).await
215 }
216}
217
218#[derive(Clone)]
219pub struct AwaitPointerEventScope {
220 state: Rc<PointerInputScopeState>,
221}
222
223impl AwaitPointerEventScope {
224 pub fn size(&self) -> Size {
227 self.state.size.get()
228 }
229
230 pub async fn await_pointer_event(&self) -> PointerEvent {
231 NextPointerEvent {
232 state: self.state.clone(),
233 }
234 .await
235 }
236}
237
238struct NextPointerEvent {
239 state: Rc<PointerInputScopeState>,
240}
241
242impl Future for NextPointerEvent {
243 type Output = PointerEvent;
244
245 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
246 self.state.poll_event(cx)
247 }
248}
249
250struct PointerInputScopeState {
251 events: RefCell<VecDeque<PointerEvent>>,
252 waiting: RefCell<Option<Waker>>,
253 size: Rc<Cell<Size>>,
258}
259
260impl PointerInputScopeState {
261 fn new(size: Rc<Cell<Size>>) -> Self {
262 Self {
263 events: RefCell::new(VecDeque::new()),
264 waiting: RefCell::new(None),
265 size,
266 }
267 }
268
269 fn push_event(&self, event: PointerEvent) {
270 self.events.borrow_mut().push_back(event);
271 let waker = {
272 let mut waiting = self.waiting.borrow_mut();
273 waiting.take()
274 };
275 if let Some(waker) = waker {
276 waker.wake();
277 }
278 }
279
280 fn poll_event(&self, cx: &mut Context<'_>) -> Poll<PointerEvent> {
281 if let Some(event) = self.events.borrow_mut().pop_front() {
282 Poll::Ready(event)
283 } else {
284 self.waiting.replace(Some(cx.waker().clone()));
285 Poll::Pending
286 }
287 }
288}
289
290struct PointerEventDispatcher {
291 state: Rc<RefCell<Option<Rc<PointerInputScopeState>>>>,
292 handler: Rc<dyn Fn(PointerEvent)>,
293}
294
295impl PointerEventDispatcher {
296 fn new() -> Self {
297 let state = Rc::new(RefCell::new(None::<Rc<PointerInputScopeState>>));
298 let state_for_handler = state.clone();
299 let handler = Rc::new(move |event: PointerEvent| {
300 if let Some(inner) = state_for_handler.borrow().as_ref() {
301 inner.push_event(event);
302 }
303 });
304 Self { state, handler }
305 }
306
307 fn handler(&self) -> Rc<dyn Fn(PointerEvent)> {
308 self.handler.clone()
309 }
310
311 fn set_state(&self, state: Option<Rc<PointerInputScopeState>>) {
312 *self.state.borrow_mut() = state;
313 }
314}
315
316struct PointerInputTask {
317 id: u64,
318 owner: PointerInputTaskOwner,
319 inner: Rc<PointerInputTaskInner>,
320}
321
322impl PointerInputTask {
323 fn new(future: PointerInputFuture) -> Self {
324 let inner = Rc::new(PointerInputTaskInner::new(future));
325 let id = Rc::as_ptr(&inner) as usize as u64;
326 let owner = crate::render_state::register_pointer_input_task(id, inner.clone());
327 Self { id, owner, inner }
328 }
329
330 fn poll(&self) {
331 self.inner.poll(self.owner, self.id);
332 }
333
334 fn cancel(self) {
335 self.inner.cancel();
336 crate::render_state::remove_pointer_input_task(self.owner, self.id);
337 }
338}
339
340impl Drop for PointerInputTask {
341 fn drop(&mut self) {
342 self.inner.cancel();
343 crate::render_state::remove_pointer_input_task(self.owner, self.id);
344 }
345}
346
347pub(crate) struct PointerInputTaskInner {
348 future: RefCell<Option<PointerInputFuture>>,
349 is_polling: Cell<bool>,
350 needs_poll: Cell<bool>,
351}
352
353impl PointerInputTaskInner {
354 fn new(future: PointerInputFuture) -> Self {
355 Self {
356 future: RefCell::new(Some(future)),
357 is_polling: Cell::new(false),
358 needs_poll: Cell::new(false),
359 }
360 }
361
362 fn cancel(&self) {
363 self.future.borrow_mut().take();
364 }
365
366 fn request_poll(&self, owner: PointerInputTaskOwner, task_id: u64) {
367 if self.is_polling.get() {
368 self.needs_poll.set(true);
369 } else {
370 self.poll(owner, task_id);
371 }
372 }
373
374 fn poll(&self, owner: PointerInputTaskOwner, task_id: u64) {
375 if self.is_polling.replace(true) {
376 self.needs_poll.set(true);
377 return;
378 }
379 loop {
380 self.needs_poll.set(false);
381 let waker = waker(Arc::new(PointerInputTaskWaker { task_id, owner }));
382 let mut cx = Context::from_waker(&waker);
383 let mut future_slot = self.future.borrow_mut();
384 if let Some(future) = future_slot.as_mut() {
385 let poll_result = future.as_mut().poll(&mut cx);
386 if poll_result.is_ready() {
387 future_slot.take();
388 }
389 }
390 if !self.needs_poll.get() {
391 break;
392 }
393 }
394 self.is_polling.set(false);
395 }
396}
397
398struct PointerInputTaskWaker {
399 task_id: u64,
400 owner: PointerInputTaskOwner,
401}
402
403impl ArcWake for PointerInputTaskWaker {
404 fn wake_by_ref(arc_self: &Arc<Self>) {
405 crate::render_state::request_pointer_input_task_poll(arc_self.owner, arc_self.task_id);
406 }
407}
408
409pub struct SuspendingPointerInputNode {
410 site: KeyToken,
413 keys: Vec<KeyToken>,
414 handler: PointerInputHandler,
415 dispatcher: PointerEventDispatcher,
416 task: Option<PointerInputTask>,
417 layout_size: Rc<Cell<Size>>,
422 state: NodeState,
423}
424
425impl SuspendingPointerInputNode {
426 fn new(site: KeyToken, keys: Vec<KeyToken>, handler: PointerInputHandler) -> Self {
427 Self {
428 site,
429 keys,
430 handler,
431 dispatcher: PointerEventDispatcher::new(),
432 task: None,
433 layout_size: Rc::new(Cell::new(Size {
434 width: 0.0,
435 height: 0.0,
436 })),
437 state: NodeState::new(),
438 }
439 }
440
441 fn update(&mut self, site: KeyToken, keys: Vec<KeyToken>, handler: PointerInputHandler) {
442 let should_restart = self.site != site || self.keys != keys;
451 self.site = site;
452 self.keys = keys;
453 self.handler = handler; if should_restart {
455 self.restart();
456 }
457 }
458
459 fn restart(&mut self) {
460 self.cancel();
461 self.start();
462 }
463
464 fn start(&mut self) {
465 let state = Rc::new(PointerInputScopeState::new(self.layout_size.clone()));
466 self.dispatcher.set_state(Some(state.clone()));
467 let scope = PointerInputScope::new(state);
468 let future = (self.handler)(scope);
469 let task = PointerInputTask::new(future);
470 task.poll();
471 self.task = Some(task);
472 }
473
474 fn cancel(&mut self) {
475 if let Some(task) = self.task.take() {
476 task.cancel();
477 }
478 self.dispatcher.set_state(None);
479 }
480}
481
482impl Drop for SuspendingPointerInputNode {
483 fn drop(&mut self) {
484 self.cancel();
485 }
486}
487
488impl ModifierNode for SuspendingPointerInputNode {
489 fn on_attach(&mut self, _context: &mut dyn ModifierNodeContext) {
490 self.start();
491 }
492
493 fn on_detach(&mut self) {
494 self.cancel();
495 }
496
497 fn on_reset(&mut self) {
498 }
502
503 impl_pointer_input_node!();
505}
506
507impl DelegatableNode for SuspendingPointerInputNode {
508 fn node_state(&self) -> &NodeState {
509 &self.state
510 }
511}
512
513impl PointerInputNode for SuspendingPointerInputNode {
514 fn pointer_input_handler(&self) -> Option<Rc<dyn Fn(PointerEvent)>> {
515 Some(self.dispatcher.handler())
516 }
517
518 fn layout_size_sink(&self) -> Option<Rc<Cell<Size>>> {
519 Some(self.layout_size.clone())
520 }
521}
522
523#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
524struct KeyToken {
525 type_id: TypeId,
526 hash: u64,
527}
528
529impl KeyToken {
530 fn declaration_site(site: &'static std::panic::Location<'static>) -> Self {
531 Self::new(&(site.file(), site.line(), site.column()))
532 }
533
534 fn new<T: Hash + 'static>(value: &T) -> Self {
535 let mut hasher = default::new();
536 value.hash(&mut hasher);
537 Self {
538 type_id: TypeId::of::<T>(),
539 hash: hasher.finish(),
540 }
541 }
542}