use super::gesture_recognizers::GestureRecognizer;
use super::{
IPointer, InputElement, PointerCaptureChangingEventArgs, PointerCaptureLostEventArgs, PointerType,
};
use crate::reactive::IDisposable;
use crate::{Ref, Visual, VisualTreeAttachmentEventArgs};
use std::any::Any;
use std::cell::{Cell, RefCell};
use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicI32, Ordering};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum CaptureSource {
Explicit,
Implicit,
Platform,
}
static NEXT_FREE_POINTER_ID: AtomicI32 = AtomicI32::new(1000);
type PlatformCapture = Box<dyn Fn(Option<&Ref<InputElement>>)>;
pub struct Pointer {
this: Weak<Pointer>,
id: i32,
type_: PointerType,
is_primary: bool,
disposed: Cell<bool>,
captured: RefCell<Option<Ref<InputElement>>>,
captured_gesture_recognizer: RefCell<Option<Ref<GestureRecognizer>>>,
capture_source: Cell<CaptureSource>,
is_gesture_recognition_skipped: Cell<bool>,
capture_detached: RefCell<Option<Rc<dyn IDisposable>>>,
platform_capture: Option<PlatformCapture>,
}
impl Pointer {
pub fn get_next_free_id() -> i32 {
NEXT_FREE_POINTER_ID.fetch_add(1, Ordering::Relaxed)
}
pub fn new(id: i32, type_: PointerType, is_primary: bool) -> Rc<Pointer> {
Self::create(id, type_, is_primary, None)
}
pub fn with_platform_capture(
id: i32,
type_: PointerType,
is_primary: bool,
platform_capture: impl Fn(Option<&Ref<InputElement>>) + 'static,
) -> Rc<Pointer> {
Self::create(id, type_, is_primary, Some(Box::new(platform_capture)))
}
fn create(id: i32, type_: PointerType, is_primary: bool, platform_capture: Option<PlatformCapture>) -> Rc<Pointer> {
Rc::new_cyclic(|this| Pointer {
this: this.clone(),
id,
type_,
is_primary,
disposed: Cell::new(false),
captured: RefCell::new(None),
captured_gesture_recognizer: RefCell::new(None),
capture_source: Cell::new(CaptureSource::Platform),
is_gesture_recognition_skipped: Cell::new(false),
capture_detached: RefCell::new(None),
platform_capture,
})
}
fn find_common_parent(
control1: Option<&Ref<InputElement>>,
control2: Option<&Ref<InputElement>>,
) -> Option<Ref<InputElement>> {
let (c1, c2) = (control1?, control2?);
c2.get_self_and_visual_ancestors()
.filter_map(|v| v.downcast::<InputElement>().ok())
.find(|candidate| candidate == c1 || candidate.is_visual_ancestor_of(c1))
}
fn platform_capture(&self, element: Option<&Ref<InputElement>>) {
if let Some(platform_capture) = &self.platform_capture {
platform_capture(element);
}
}
pub fn platform_capture_lost(&self) {
self.capture_lost(CaptureSource::Platform);
}
pub(crate) fn capture_lost(&self, source: CaptureSource) {
if self.disposed.get() {
return;
}
self.capture_lost_core(source);
}
fn capture_lost_core(&self, source: CaptureSource) {
self.capture_core(None, None, source);
self.is_gesture_recognition_skipped.set(false);
}
pub fn capture_with_source(&self, control: Option<&Ref<InputElement>>, source: CaptureSource) {
if self.disposed.get() {
debug_assert!(control.is_none(), "Capturing a pointer that no longer exists.");
return;
}
self.capture_core(control.cloned(), None, source);
}
fn effective_capturer(&self) -> Option<Ref<InputElement>> {
self.captured_gesture_recognizer().and_then(|recognizer| recognizer.target()).or_else(|| self.captured())
}
pub fn captured_gesture_recognizer(&self) -> Option<Ref<GestureRecognizer>> {
self.captured_gesture_recognizer.borrow().clone()
}
fn capture_core(
&self,
control: Option<Ref<InputElement>>,
gesture_recognizer: Option<Ref<GestureRecognizer>>,
source: CaptureSource,
) {
let old_capture = self.captured();
let old_gesture_recognizer = self.captured_gesture_recognizer();
let old_source = self.capture_source.get();
let old_effective_capturer = self.effective_capturer();
if old_capture == control && old_gesture_recognizer == gesture_recognizer && old_source == source {
return;
}
let this: Rc<dyn IPointer> = match self.this.upgrade() {
Some(this) => this,
None => return,
};
let mut common_parent = None;
if old_capture.is_some() || control.is_some() {
common_parent = Self::find_common_parent(control.as_ref(), old_capture.as_ref());
let visual: &Visual = old_capture.as_ref().or(control.as_ref()).expect("one of them is set");
for notify_target in
visual.get_self_and_visual_ancestors().filter_map(|v| v.downcast::<InputElement>().ok())
{
let args = PointerCaptureChangingEventArgs::new(¬ify_target, this.clone(), control.clone(), source);
notify_target.raise_event(&args);
if args.handled() {
return;
}
if Some(¬ify_target) == common_parent.as_ref() {
break;
}
}
}
if old_capture.is_some() {
let subscription = self.capture_detached.take();
if let Some(subscription) = subscription {
subscription.dispose();
}
}
let this_pointer = this.clone();
if old_gesture_recognizer != gesture_recognizer {
if let Some(old) = &old_gesture_recognizer {
old.pointer_capture_lost_internal(&this_pointer);
}
}
drop(self.captured.replace(control.clone()));
drop(self.captured_gesture_recognizer.replace(gesture_recognizer));
self.capture_source.set(source);
let effective_capturer = self.effective_capturer();
if old_effective_capturer != effective_capturer && source != CaptureSource::Platform {
self.platform_capture(effective_capturer.as_ref());
}
if let Some(old_visual) = &old_capture {
for notify_target in
old_visual.get_self_and_visual_ancestors().filter_map(|v| v.downcast::<InputElement>().ok())
{
if Some(¬ify_target) == common_parent.as_ref() {
break;
}
notify_target.raise_event(&PointerCaptureLostEventArgs::new(¬ify_target, this.clone()));
}
}
if let Some(new_visual) = &control {
let weak = self.this.clone();
let subscription = new_visual.detached_from_visual_tree(move |e| {
if let Some(pointer) = weak.upgrade() {
pointer.on_capture_detached(e);
}
});
let old = self.capture_detached.replace(Some(subscription));
if let Some(old) = old {
old.dispose();
}
}
if self.captured.borrow().is_none() && self.captured_gesture_recognizer.borrow().is_none() {
self.is_gesture_recognition_skipped.set(false);
}
if self.type_ != PointerType::Touch {
let old_input_root = old_capture.as_ref().and_then(|v| v.get_input_root());
let new_input_root = control.as_ref().and_then(|v| v.get_input_root());
if let Some(old_input_root) = &old_input_root {
old_input_root.pointer_over_invalidated();
}
let same_root = match (&old_input_root, &new_input_root) {
(Some(a), Some(b)) => std::ptr::addr_eq(Rc::as_ptr(a), Rc::as_ptr(b)),
(None, None) => true,
_ => false,
};
if !same_root {
if let Some(new_input_root) = &new_input_root {
new_input_root.pointer_over_invalidated();
}
}
}
}
fn get_next_capture(parent: Option<&Ref<Visual>>) -> Option<Ref<InputElement>> {
parent.and_then(|parent| parent.find_ancestor_of_type::<InputElement>(true))
}
fn on_capture_detached(&self, e: &VisualTreeAttachmentEventArgs) {
let next = Self::get_next_capture(e.attachment_point());
self.capture(next.as_ref());
}
pub(crate) fn capture_gesture_recognizer(&self, gesture_recognizer: Option<&Ref<GestureRecognizer>>) {
if self.disposed.get() {
debug_assert!(
gesture_recognizer.is_none(),
"Capturing a pointer that no longer exists to a gesture recognizer."
);
return;
}
self.capture_core(None, gesture_recognizer.cloned(), CaptureSource::Explicit);
}
pub fn capture_source(&self) -> CaptureSource {
self.capture_source.get()
}
pub fn is_gesture_recognition_skipped(&self) -> bool {
self.is_gesture_recognition_skipped.get()
}
pub fn set_is_gesture_recognition_skipped(&self, value: bool) {
self.is_gesture_recognition_skipped.set(value)
}
pub fn dispose(&self) {
if self.disposed.get() {
return;
}
self.disposed.set(true);
self.capture_lost_core(CaptureSource::Platform);
}
}
impl IPointer for Pointer {
fn id(&self) -> i32 {
self.id
}
fn capture(&self, control: Option<&Ref<InputElement>>) {
self.capture_with_source(control, CaptureSource::Explicit);
}
fn captured(&self) -> Option<Ref<InputElement>> {
self.captured.borrow().clone()
}
fn type_(&self) -> PointerType {
self.type_
}
fn is_primary(&self) -> bool {
self.is_primary
}
fn as_any(&self) -> &dyn Any {
self
}
}