use crate::app::App;
use crate::event_loop::{ AppData, SurfaceFocus, SurfaceState };
use crate::tree::find_handlers;
use crate::platform::Platform;
use super::event::{ TouchInput, TouchPhase };
impl<A: App, P: Platform> AppData<A, P>
{
pub( crate ) fn touch_input( &mut self, input: &TouchInput )
{
match input.phase
{
TouchPhase::Down { focus, position } => self.touch_down( focus, input.id, input.time, position ),
TouchPhase::Motion { position } => self.touch_motion( input.id, input.time, position ),
TouchPhase::Up => self.touch_up( input.id, input.time ),
}
}
fn touch_down( &mut self, focus: SurfaceFocus, id: i32, time: u32, position: ( f64, f64 ) )
{
self.touch_focus.insert( id, focus );
let pos = self.surface( focus ).to_physical( position.0, position.1 );
let raw_here = matches!( focus, SurfaceFocus::Main ) && self.app.claims_raw_touch_at( pos.x, pos.y );
if !self.app.claims_raw_touch() && !raw_here
{
let takeover =
{
let ss = self.surface( focus );
ss.primary_touch_id.is_some_and( |primary| primary != id ) && ss.gesture.is_plain_press()
};
if takeover
{
self.release_primary( focus );
}
}
self.pointer_pos = pos;
if self.app.claims_raw_touch()
{
self.surface_mut( focus ).touch_slots.insert( id, pos );
self.app.on_touch_down( id as i64, pos.x, pos.y );
return;
}
if raw_here
{
self.set_focus( focus, None );
self.surface_mut( focus ).touch_slots.insert( id, pos );
self.app.on_touch_down( id as i64, pos.x, pos.y );
return;
}
if self.surface( focus ).primary_touch_id == Some( id )
{
return;
}
let is_primary =
{
let ss = self.surface_mut( focus );
if ss.primary_touch_id.is_none()
{
ss.primary_touch_id = Some( id );
true
}
else
{
ss.touch_slots.insert( id, pos );
false
}
};
if !is_primary
{
self.app.on_touch_down( id as i64, pos.x, pos.y );
return;
}
if matches!( focus, SurfaceFocus::Main ) && !self.overlays.is_empty()
{
self.dismiss_main_outside_popups( pos );
}
if self.surface( focus ).context_menu.is_some() && self.handle_context_menu_press( focus, pos ) { return; }
if self.osk_press( focus, pos ) { return; }
self.app.on_pointer_move( pos.x, pos.y );
self.app.on_pointer_button( pos.x, pos.y, true );
let outcome =
{
let ss = self.surface_mut( focus );
let result = ss.gesture.on_press( pos, &ss.frame.widget_rects, &ss.frame.scroll_rects );
ss.gesture.fling_x.push( time, pos.x );
ss.needs_redraw = true;
result
};
self.press_on_focused = outcome.hit_idx.is_some() && self.surface( focus ).focused_idx == outcome.hit_idx;
self.focus_pressed( focus, outcome.hit_idx );
self.osk_after_press( focus, outcome.hit_idx );
if let Some( msg ) = outcome.initial_slider_msg
{
self.pending_msgs.push( msg );
}
if let Some( idx ) = outcome.hit_idx
{
let immediate = {
let handlers = find_handlers( &self.surface( focus ).frame.widget_rects, idx );
if matches!( handlers, Some( crate::widget::WidgetHandlers::Button { repeating: true, .. } ) )
{
handlers.and_then( |h| h.press_msg() )
} else { None }
};
if let Some( msg ) = immediate
{
self.pending_msgs.push( msg );
self.start_button_repeat( focus, idx );
}
}
if let Some( idx ) = outcome.hit_idx
{
let is_text = find_handlers( &self.surface( focus ).frame.widget_rects, idx )
.map( |h| h.is_text_input() ).unwrap_or( false );
if is_text
{
if self.handle_password_toggle_press( focus, idx, pos ) || self.handle_text_scrollbar_press( focus, idx, pos )
{
let _ = self.note_press_for_double_click( pos );
}
else
{
let is_double = self.note_press_for_double_click( pos );
if is_double
{
self.handle_text_select_word( focus, idx, pos );
} else {
self.handle_text_pointer_down( focus, idx, pos );
}
}
} else {
let _ = self.note_press_for_double_click( pos );
}
} else {
let _ = self.note_press_for_double_click( pos );
}
}
fn touch_up( &mut self, id: i32, time: u32 )
{
let focus = self.touch_focus.remove( &id ).unwrap_or( SurfaceFocus::Main );
if self.app.claims_raw_touch()
{
let pos =
{
let ss = self.surface_mut( focus );
ss.touch_slots.remove( &id ).unwrap_or( self.pointer_pos )
};
self.app.on_touch_up( id as i64, pos.x, pos.y );
return;
}
let is_primary =
{
let ss = self.surface_mut( focus );
ss.primary_touch_id == Some( id )
};
if !is_primary
{
let pos =
{
let ss = self.surface_mut( focus );
ss.touch_slots.remove( &id ).unwrap_or( self.pointer_pos )
};
self.app.on_touch_up( id as i64, pos.x, pos.y );
return;
}
let x = self.pointer_pos.x;
self.surface_mut( focus ).gesture.fling_x.push( time, x );
self.release_primary( focus );
}
fn touch_motion( &mut self, id: i32, time: u32, position: ( f64, f64 ) )
{
let focus = *self.touch_focus.get( &id ).unwrap_or( &SurfaceFocus::Main );
let pp = self.surface( focus ).to_physical( position.0, position.1 );
if self.app.claims_raw_touch()
{
self.pointer_pos = pp;
{
let ss = self.surface_mut( focus );
ss.touch_slots.insert( id, pp );
}
self.app.on_touch_move( id as i64, pp.x, pp.y );
return;
}
let is_primary =
{
let ss = self.surface( focus );
ss.primary_touch_id == Some( id )
};
if !is_primary
{
{
let ss = self.surface_mut( focus );
ss.touch_slots.insert( id, pp );
}
self.app.on_touch_move( id as i64, pp.x, pp.y );
return;
}
self.pointer_pos = pp;
self.app.on_pointer_move( pp.x, pp.y );
if self.osk_move( focus, pp ) { return; }
let global_drag = self.has_active_long_press_drag();
let swipe = self.swipe_config( focus );
let outcome =
{
let ss = self.surface_mut( focus );
ss.gesture.fling_x.push( time, pp.x );
ss.gesture.on_move( pp, &ss.frame.widget_rects, &mut ss.frame.scroll_offsets, &swipe, global_drag )
};
self.apply_move_outcome( focus, outcome );
let pressed_text = self.surface( focus ).gesture.pressed_idx
.and_then( |idx|
{
let is_text = find_handlers( &self.surface( focus ).frame.widget_rects, idx )
.map( |h| h.is_text_input() ).unwrap_or( false );
if is_text { Some( idx ) } else { None }
} );
if let Some( idx ) = pressed_text
{
if !self.handle_text_scrollbar_drag( focus, idx, pp )
{
self.handle_text_pointer_drag( focus, idx, pp );
}
}
}
fn release_primary( &mut self, focus: SurfaceFocus )
{
let pos = self.pointer_pos;
if self.osk_release( focus, pos )
{
self.surface_mut( focus ).primary_touch_id = None;
return;
}
self.app.on_pointer_button( pos.x, pos.y, false );
let global_drag = self.has_active_long_press_drag();
let swipe = self.swipe_config( focus );
let events_out =
{
let ss = self.surface_mut( focus );
ss.needs_redraw = true;
ss.primary_touch_id = None;
ss.gesture.on_release( pos, &ss.frame.widget_rects, &swipe, global_drag )
};
self.apply_release_events( focus, events_out );
self.stop_button_repeat();
}
pub( crate ) fn reset_touch_state( &mut self ) -> bool
{
let had_state = self.main.primary_touch_id.is_some()
|| !self.main.touch_slots.is_empty()
|| !self.touch_focus.is_empty()
|| self.overlays.values().any( |ss| ss.primary_touch_id.is_some() || !ss.touch_slots.is_empty() );
let mut aux_releases: Vec<( i32, crate::types::Point )> = Vec::new();
let collect = |ss: &mut SurfaceState<A::Message, P::Surface>, out: &mut Vec<( i32, crate::types::Point )>|
{
for ( id, pos ) in ss.touch_slots.drain() { out.push( ( id, pos ) ); }
ss.primary_touch_id = None;
ss.gesture.on_cancel();
};
self.cancel_osk_presses();
collect( &mut self.main, &mut aux_releases );
for ss in self.overlays.values_mut()
{
collect( ss, &mut aux_releases );
}
self.touch_focus.clear();
for ( id, pos ) in aux_releases
{
self.app.on_touch_up( id as i64, pos.x, pos.y );
}
self.stop_button_repeat();
had_state
}
}