@@ -65,38 +65,104 @@ impl Default for LoginDialogState {
6565 }
6666}
6767
68- // #[cfg(target_os = "android")]
69- pub fn touch_camera (
68+ /// Handle touch input for panning on mobile devices
69+ #[ cfg( target_os = "android" ) ]
70+ pub fn handle_touch_camera (
71+ mut contexts : EguiContexts ,
7072 windows : Query < & Window > ,
7173 mut touches : EventReader < TouchInput > ,
72- mut camera : Query < & mut Transform , With < Camera3d > > ,
74+ mut camera : Query < & mut Transform , With < Camera2d > > ,
7375 mut last_position : Local < Option < Vec2 > > ,
74- mut rotations : EventReader < RotationGesture > ,
7576) {
76- let window = windows. single ( ) . unwrap ( ) ;
77+ // Don't handle touch if egui wants the input
78+ let Ok ( ctx) = contexts. ctx_mut ( ) else {
79+ return ;
80+ } ;
81+ if ctx. wants_pointer_input ( ) || ctx. is_pointer_over_area ( ) {
82+ touches. clear ( ) ;
83+ * last_position = None ;
84+ return ;
85+ }
86+
87+ let Ok ( window) = windows. single ( ) else {
88+ return ;
89+ } ;
7790
7891 for touch in touches. read ( ) {
7992 if touch. phase == TouchPhase :: Started {
8093 * last_position = None ;
8194 }
82- if let Some ( last_position) = * last_position {
83- let mut transform = camera. single_mut ( ) . unwrap ( ) ;
84- * transform = Transform :: from_xyz (
85- transform. translation . x
86- + ( touch. position . x - last_position. x ) / window. width ( ) * 5.0 ,
87- transform. translation . y ,
88- transform. translation . z
89- + ( touch. position . y - last_position. y ) / window. height ( ) * 5.0 ,
90- )
91- . looking_at ( Vec3 :: ZERO , Vec3 :: Y ) ;
95+ if let Some ( last_pos) = * last_position {
96+ if let Ok ( mut transform) = camera. single_mut ( ) {
97+ // Calculate displacement in screen space
98+ let displacement = touch. position - last_pos;
99+ // Apply panning (negative Y because screen coords are flipped)
100+ transform. translation -= Vec3 :: new ( displacement. x , -displacement. y , 0.0 ) ;
101+ }
92102 }
93103 * last_position = Some ( touch. position ) ;
94104 }
95- // Rotation gestures only work on iOS
96- for rotation in rotations. read ( ) {
97- let mut transform = camera. single_mut ( ) . unwrap ( ) ;
98- let forward = transform. forward ( ) ;
99- transform. rotate_axis ( forward, rotation. 0 / 10.0 ) ;
105+ }
106+
107+ /// Handle pinch-to-zoom gestures on mobile devices using two-finger touch
108+ #[ cfg( target_os = "android" ) ]
109+ pub fn handle_touch_zoom (
110+ mut contexts : EguiContexts ,
111+ mut touches : EventReader < TouchInput > ,
112+ mut zoom_level : ResMut < ZoomLevel > ,
113+ mut camera_query : Query < & mut Projection , With < Camera2d > > ,
114+ mut touch_positions : Local < std:: collections:: HashMap < u64 , Vec2 > > ,
115+ mut last_distance : Local < Option < f32 > > ,
116+ ) {
117+ // Don't handle zoom if egui wants the input
118+ let Ok ( ctx) = contexts. ctx_mut ( ) else {
119+ return ;
120+ } ;
121+ if ctx. wants_pointer_input ( ) || ctx. is_pointer_over_area ( ) {
122+ touches. clear ( ) ;
123+ touch_positions. clear ( ) ;
124+ * last_distance = None ;
125+ return ;
126+ }
127+
128+ // Update touch positions
129+ for touch in touches. read ( ) {
130+ match touch. phase {
131+ TouchPhase :: Started | TouchPhase :: Moved => {
132+ touch_positions. insert ( touch. id , touch. position ) ;
133+ }
134+ TouchPhase :: Ended | TouchPhase :: Canceled => {
135+ touch_positions. remove ( & touch. id ) ;
136+ if touch_positions. len ( ) < 2 {
137+ * last_distance = None ;
138+ }
139+ }
140+ }
141+ }
142+
143+ // Only process zoom if we have exactly 2 touches
144+ if touch_positions. len ( ) == 2 {
145+ let positions: Vec < Vec2 > = touch_positions. values ( ) . copied ( ) . collect ( ) ;
146+ let current_distance = positions[ 0 ] . distance ( positions[ 1 ] ) ;
147+
148+ if let Some ( prev_distance) = * last_distance {
149+ // Calculate zoom factor based on distance change
150+ let distance_ratio = current_distance / prev_distance;
151+ let zoom_factor = 1.0 / distance_ratio;
152+ let new_zoom = ( zoom_level. 0 * zoom_factor) . clamp ( CAMERA_ZOOM_RANGE . start , CAMERA_ZOOM_RANGE . end ) ;
153+
154+ if let Ok ( mut projection) = camera_query. single_mut ( ) {
155+ if let Projection :: Orthographic ( ortho) = projection. as_mut ( ) {
156+ ortho. scale = new_zoom;
157+ }
158+ }
159+
160+ * * zoom_level = new_zoom;
161+ }
162+
163+ * last_distance = Some ( current_distance) ;
164+ } else {
165+ * last_distance = None ;
100166 }
101167}
102168
0 commit comments