@@ -6,10 +6,11 @@ use blitz_traits::events::{
66use dioxus_html:: {
77 AnimationData , BeforeInputData , CancelData , ClipboardData , CompositionData , DragData ,
88 FocusData , FormData , FormValue , HasFileData , HasFocusData , HasFormData , HasKeyboardData ,
9- HasMouseData , HasPointerData , HasScrollData , HasWheelData , HtmlEventConverter , ImageData ,
10- KeyboardData , MediaData , MountedData , MountedError , MountedResult , MouseData ,
11- PlatformEventData , PointerData , RenderedElementBacking , ResizeData , ScrollBehavior , ScrollData ,
12- ScrollToOptions , SelectionData , ToggleData , TouchData , TransitionData , VisibleData , WheelData ,
9+ HasMouseData , HasPointerData , HasScrollData , HasTouchData , HasTouchPointData , HasWheelData ,
10+ HtmlEventConverter , ImageData , KeyboardData , MediaData , MountedData , MountedError ,
11+ MountedResult , MouseData , PlatformEventData , PointerData , RenderedElementBacking , ResizeData ,
12+ ScrollBehavior , ScrollData , ScrollToOptions , SelectionData , ToggleData , TouchData , TouchPoint ,
13+ TransitionData , VisibleData , WheelData ,
1314 geometry:: {
1415 ClientPoint , ElementPoint , PagePoint , PixelsRect , PixelsSize , PixelsVector2D , ScreenPoint ,
1516 WheelDelta ,
@@ -117,8 +118,8 @@ impl HtmlEventConverter for NativeConverter {
117118 unimplemented ! ( "todo: convert_toggle_data in dioxus-native. requires support in blitz" )
118119 }
119120
120- fn convert_touch_data ( & self , _event : & PlatformEventData ) -> TouchData {
121- unimplemented ! ( "todo: convert_touch_data in dioxus-native. requires support in blitz" )
121+ fn convert_touch_data ( & self , event : & PlatformEventData ) -> TouchData {
122+ event . downcast :: < NativeTouchData > ( ) . unwrap ( ) . clone ( ) . into ( )
122123 }
123124
124125 fn convert_transition_data ( & self , _event : & PlatformEventData ) -> TransitionData {
@@ -335,8 +336,7 @@ impl InteractionLocation for NativePointerData {
335336
336337impl InteractionElementOffset for NativePointerData {
337338 fn element_coordinates ( & self ) -> ElementPoint {
338- // TODO: implement element point
339- ElementPoint :: new ( 0.0 , 0.0 )
339+ ElementPoint :: new ( self . 0 . element_x ( ) as f64 , self . 0 . element_y ( ) as f64 )
340340 }
341341}
342342
@@ -417,6 +417,92 @@ impl HasPointerData for NativePointerData {
417417 }
418418}
419419
420+ /// Touch event data exposed to Dioxus Native application code.
421+ ///
422+ /// Blitz tracks input via pointer events, so a touch event is generated from the
423+ /// pointer event of the finger that triggered it (`touches_changed`). The full
424+ /// list of concurrent touches is carried on the triggering event's
425+ /// [`BlitzPointerEvent::active_pointers`] list and reported via `touches`.
426+ #[ derive( Clone ) ]
427+ pub struct NativeTouchData ( pub ( crate ) BlitzPointerEvent ) ;
428+
429+ impl ModifiersInteraction for NativeTouchData {
430+ fn modifiers ( & self ) -> Modifiers {
431+ self . 0 . mods
432+ }
433+ }
434+
435+ impl HasTouchData for NativeTouchData {
436+ fn touches ( & self ) -> Vec < TouchPoint > {
437+ // All pointers currently active on the surface (multi-touch).
438+ self . 0
439+ . active_pointers
440+ . borrow ( )
441+ . iter ( )
442+ . map ( |event| TouchPoint :: new ( NativeTouchPointData ( event. clone ( ) ) ) )
443+ . collect ( )
444+ }
445+
446+ fn touches_changed ( & self ) -> Vec < TouchPoint > {
447+ // Just the touch that triggered this event.
448+ vec ! [ TouchPoint :: new( NativeTouchPointData ( self . 0 . clone( ) ) ) ]
449+ }
450+
451+ fn target_touches ( & self ) -> Vec < TouchPoint > {
452+ // We don't track a per-touch target, so approximate `targetTouches`
453+ // (touches that started on the event target) with all active touches.
454+ self . touches ( )
455+ }
456+
457+ fn as_any ( & self ) -> & dyn Any {
458+ self as & dyn Any
459+ }
460+ }
461+
462+ #[ derive( Clone ) ]
463+ pub struct NativeTouchPointData ( BlitzPointerEvent ) ;
464+
465+ impl InteractionLocation for NativeTouchPointData {
466+ fn client_coordinates ( & self ) -> ClientPoint {
467+ ClientPoint :: new ( self . 0 . client_x ( ) as f64 , self . 0 . client_y ( ) as f64 )
468+ }
469+
470+ fn screen_coordinates ( & self ) -> ScreenPoint {
471+ ScreenPoint :: new ( self . 0 . screen_x ( ) as f64 , self . 0 . screen_y ( ) as f64 )
472+ }
473+
474+ fn page_coordinates ( & self ) -> PagePoint {
475+ PagePoint :: new ( self . 0 . page_x ( ) as f64 , self . 0 . page_y ( ) as f64 )
476+ }
477+ }
478+
479+ impl HasTouchPointData for NativeTouchPointData {
480+ fn identifier ( & self ) -> i32 {
481+ match self . 0 . id {
482+ BlitzPointerId :: Finger ( id) => id as i32 ,
483+ BlitzPointerId :: Mouse | BlitzPointerId :: Pen => 0 ,
484+ }
485+ }
486+
487+ fn force ( & self ) -> f64 {
488+ self . 0 . details . pressure
489+ }
490+
491+ fn radius ( & self ) -> ScreenPoint {
492+ // TODO: expose real touch radius once blitz tracks it
493+ ScreenPoint :: new ( 1.0 , 1.0 )
494+ }
495+
496+ fn rotation ( & self ) -> f64 {
497+ // TODO: expose real touch rotation once blitz tracks it
498+ 0.0
499+ }
500+
501+ fn as_any ( & self ) -> & dyn Any {
502+ self as & dyn Any
503+ }
504+ }
505+
420506#[ derive( Clone ) ]
421507pub struct NativeFocusData ;
422508impl HasFocusData for NativeFocusData {
@@ -500,8 +586,7 @@ impl ModifiersInteraction for NativeWheelData {
500586
501587impl InteractionElementOffset for NativeWheelData {
502588 fn element_coordinates ( & self ) -> ElementPoint {
503- // TODO: implement element point
504- ElementPoint :: new ( 0.0 , 0.0 )
589+ ElementPoint :: new ( self . 0 . element_x ( ) as f64 , self . 0 . element_y ( ) as f64 )
505590 }
506591}
507592
@@ -524,3 +609,78 @@ pub fn synthetic_click_event(node: &Node, modifiers: Modifiers) -> Box<dyn Any>
524609 node. synthetic_click_event_data ( modifiers) ,
525610 ) )
526611}
612+
613+ #[ cfg( test) ]
614+ mod tests {
615+ use super :: * ;
616+ use blitz_traits:: events:: {
617+ BlitzPointerId , MouseEventButton , MouseEventButtons , Point , PointerCoords , PointerDetails ,
618+ } ;
619+
620+ fn finger_event ( id : u64 , x : f32 , y : f32 ) -> BlitzPointerEvent {
621+ BlitzPointerEvent {
622+ id : BlitzPointerId :: Finger ( id) ,
623+ is_primary : id == 0 ,
624+ coords : PointerCoords {
625+ page_x : x,
626+ page_y : y,
627+ screen_x : x,
628+ screen_y : y,
629+ client_x : x,
630+ client_y : y,
631+ } ,
632+ button : MouseEventButton :: Main ,
633+ buttons : MouseEventButtons :: from ( MouseEventButton :: Main ) ,
634+ mods : Default :: default ( ) ,
635+ details : PointerDetails :: default ( ) ,
636+ element : Point :: default ( ) ,
637+ active_pointers : Default :: default ( ) ,
638+ }
639+ }
640+
641+ #[ test]
642+ fn touches_reports_all_active_pointers ( ) {
643+ let f0 = finger_event ( 0 , 10.0 , 20.0 ) ;
644+ let f1 = finger_event ( 1 , 30.0 , 40.0 ) ;
645+
646+ // The triggering event (second finger down) carries the list of all
647+ // currently-active pointers.
648+ let trigger = f1. clone ( ) ;
649+ {
650+ let mut list = trigger. active_pointers . borrow_mut ( ) ;
651+ list. push ( f0. clone ( ) ) ;
652+ list. push ( f1. clone ( ) ) ;
653+ }
654+
655+ let data = NativeTouchData ( trigger) ;
656+
657+ // `touches` reports every active pointer ...
658+ let touches = data. touches ( ) ;
659+ assert_eq ! ( touches. len( ) , 2 ) ;
660+ let coords: Vec < ( f64 , f64 ) > = touches
661+ . iter ( )
662+ . map ( |t| {
663+ let c = t. client_coordinates ( ) ;
664+ ( c. x , c. y )
665+ } )
666+ . collect ( ) ;
667+ assert ! ( coords. contains( & ( 10.0 , 20.0 ) ) ) ;
668+ assert ! ( coords. contains( & ( 30.0 , 40.0 ) ) ) ;
669+
670+ // ... while `changed_touches` reports only the triggering touch.
671+ assert_eq ! ( data. touches_changed( ) . len( ) , 1 ) ;
672+ let changed = data. touches_changed ( ) ;
673+ let changed_coords = changed[ 0 ] . client_coordinates ( ) ;
674+ assert_eq ! ( ( changed_coords. x, changed_coords. y) , ( 30.0 , 40.0 ) ) ;
675+ }
676+
677+ #[ test]
678+ fn touches_is_empty_when_no_pointers_are_active ( ) {
679+ // e.g. a `touchend` for the last finger: it has been removed from the
680+ // active list before dispatch, so `touches` is empty but
681+ // `changed_touches` still reports the finger that ended.
682+ let data = NativeTouchData ( finger_event ( 0 , 1.0 , 2.0 ) ) ;
683+ assert ! ( data. touches( ) . is_empty( ) ) ;
684+ assert_eq ! ( data. touches_changed( ) . len( ) , 1 ) ;
685+ }
686+ }
0 commit comments