ltk/event_loop/text_editing/
cursor.rsuse crate::app::App;
use crate::event_loop::app_data::AppData;
use crate::event_loop::surface::SurfaceFocus;
use crate::platform::Platform;
impl<A: App, P: Platform> AppData<A, P>
{
pub( crate ) fn focused_text_value( &self, focus: SurfaceFocus ) -> Option<( usize, String )>
{
let idx = self.surface( focus ).focused_idx?;
let value = if let Some( pending ) = self.surface( focus ).pending_text_values.get( &idx )
{
pending.clone()
} else {
crate::tree::find_handlers( &self.surface( focus ).frame.widget_rects, idx )?
.current_value()
.map( |s| s.to_string() )
.unwrap_or_default()
};
Some( ( idx, value ) )
}
pub( crate ) fn handle_cursor_left( &mut self, focus: SurfaceFocus, extend: bool )
{
let ( idx, value ) = match self.focused_text_value( focus ) { Some( v ) => v, None => return };
let cursor = self.surface( focus ).frame.cursor_state.get( &idx ).copied()
.unwrap_or( value.len() ).min( value.len() );
let anchor = self.surface( focus ).frame.selection_anchor.get( &idx ).copied()
.unwrap_or( cursor ).min( value.len() );
if !extend && anchor != cursor
{
let s = cursor.min( anchor );
let ss = self.surface_mut( focus );
*ss.frame.cursor_state.entry( idx ).or_insert( 0 ) = s;
*ss.frame.selection_anchor.entry( idx ).or_insert( 0 ) = s;
ss.request_redraw();
return;
}
if cursor == 0 { return; }
let prev_char = value[..cursor].chars().last();
let step = prev_char.map( |c| c.len_utf8() ).unwrap_or( 1 );
let new_cursor = cursor.saturating_sub( step );
let ss = self.surface_mut( focus );
*ss.frame.cursor_state.entry( idx ).or_insert( 0 ) = new_cursor;
if !extend { *ss.frame.selection_anchor.entry( idx ).or_insert( 0 ) = new_cursor; }
ss.request_redraw();
}
pub( crate ) fn handle_cursor_right( &mut self, focus: SurfaceFocus, extend: bool )
{
let ( idx, value ) = match self.focused_text_value( focus ) { Some( v ) => v, None => return };
let cursor = self.surface( focus ).frame.cursor_state.get( &idx ).copied()
.unwrap_or( value.len() ).min( value.len() );
let anchor = self.surface( focus ).frame.selection_anchor.get( &idx ).copied()
.unwrap_or( cursor ).min( value.len() );
if !extend && anchor != cursor
{
let e = cursor.max( anchor );
let ss = self.surface_mut( focus );
*ss.frame.cursor_state.entry( idx ).or_insert( 0 ) = e;
*ss.frame.selection_anchor.entry( idx ).or_insert( 0 ) = e;
ss.request_redraw();
return;
}
if cursor >= value.len() { return; }
let next_char = value[cursor..].chars().next();
let step = next_char.map( |c| c.len_utf8() ).unwrap_or( 1 );
let new_cursor = ( cursor + step ).min( value.len() );
let ss = self.surface_mut( focus );
*ss.frame.cursor_state.entry( idx ).or_insert( 0 ) = new_cursor;
if !extend { *ss.frame.selection_anchor.entry( idx ).or_insert( 0 ) = new_cursor; }
ss.request_redraw();
}
pub( crate ) fn handle_cursor_up( &mut self, focus: SurfaceFocus, extend: bool ) -> bool
{
let ( idx, value ) = match self.focused_text_value( focus ) { Some( v ) => v, None => return false };
let cursor = self.surface( focus ).frame.cursor_state.get( &idx ).copied()
.unwrap_or( value.len() ).min( value.len() );
let ( rect, _, multiline, secure, _align, font ) = match self.text_input_geometry( focus, idx )
{
Some( g ) => g,
None => return false,
};
if !multiline || secure { return false; }
let canvas = match self.surface( focus ).canvas.as_ref() { Some( c ) => c, None => return false };
let new_cursor = match crate::widget::text_edit::cursor_visual_up( canvas, rect, &value, cursor, &font )
{
Some( n ) => n,
None => return false,
};
let ss = self.surface_mut( focus );
*ss.frame.cursor_state.entry( idx ).or_insert( 0 ) = new_cursor;
if !extend { *ss.frame.selection_anchor.entry( idx ).or_insert( 0 ) = new_cursor; }
ss.request_redraw();
true
}
pub( crate ) fn handle_cursor_down( &mut self, focus: SurfaceFocus, extend: bool ) -> bool
{
let ( idx, value ) = match self.focused_text_value( focus ) { Some( v ) => v, None => return false };
let cursor = self.surface( focus ).frame.cursor_state.get( &idx ).copied()
.unwrap_or( value.len() ).min( value.len() );
let ( rect, _, multiline, secure, _align, font ) = match self.text_input_geometry( focus, idx )
{
Some( g ) => g,
None => return false,
};
if !multiline || secure { return false; }
let canvas = match self.surface( focus ).canvas.as_ref() { Some( c ) => c, None => return false };
let new_cursor = match crate::widget::text_edit::cursor_visual_down( canvas, rect, &value, cursor, &font )
{
Some( n ) => n,
None => return false,
};
let ss = self.surface_mut( focus );
*ss.frame.cursor_state.entry( idx ).or_insert( 0 ) = new_cursor;
if !extend { *ss.frame.selection_anchor.entry( idx ).or_insert( 0 ) = new_cursor; }
ss.request_redraw();
true
}
pub( crate ) fn handle_cursor_page( &mut self, focus: SurfaceFocus, up: bool, extend: bool ) -> bool
{
let Some( ( idx, value ) ) = self.focused_text_value( focus ) else { return false };
let Some( ( rect, _, true, false, _, font ) ) = self.text_input_geometry( focus, idx ) else { return false };
let cursor = self.surface( focus ).frame.cursor_state.get( &idx ).copied()
.unwrap_or( value.len() ).min( value.len() );
let scroll = self.text_scroll( focus, idx );
let Some( canvas ) = self.surface( focus ).canvas.as_ref() else { return false };
let ( moved, scroll ) = crate::widget::text_edit::cursor_visual_page( canvas, rect, &value, cursor, &font, scroll, up );
let ss = self.surface_mut( focus );
ss.frame.cursor_state.insert( idx, moved );
if !extend { ss.frame.selection_anchor.insert( idx, moved ); }
ss.frame.text_scroll.insert( idx, scroll );
ss.request_redraw();
true
}
pub( crate ) fn handle_cursor_home( &mut self, focus: SurfaceFocus, extend: bool )
{
let ( idx, value ) = match self.focused_text_value( focus ) { Some( v ) => v, None => return };
let cursor = self.surface( focus ).frame.cursor_state.get( &idx ).copied()
.unwrap_or( value.len() ).min( value.len() );
let new_cursor = match self.text_input_geometry( focus, idx )
{
Some( ( rect, _, true, false, _, font ) ) => match self.surface( focus ).canvas.as_ref()
{
Some( canvas ) => crate::widget::text_edit::cursor_visual_home( canvas, rect, &value, cursor, &font ),
None => value[..cursor].rfind( '\n' ).map( |p| p + 1 ).unwrap_or( 0 ),
},
_ => value[..cursor].rfind( '\n' ).map( |p| p + 1 ).unwrap_or( 0 ),
};
let ss = self.surface_mut( focus );
*ss.frame.cursor_state.entry( idx ).or_insert( 0 ) = new_cursor;
if !extend { *ss.frame.selection_anchor.entry( idx ).or_insert( 0 ) = new_cursor; }
ss.request_redraw();
}
pub( crate ) fn handle_cursor_end( &mut self, focus: SurfaceFocus, extend: bool )
{
let ( idx, value ) = match self.focused_text_value( focus ) { Some( v ) => v, None => return };
let cursor = self.surface( focus ).frame.cursor_state.get( &idx ).copied()
.unwrap_or( value.len() ).min( value.len() );
let new_cursor = match self.text_input_geometry( focus, idx )
{
Some( ( rect, _, true, false, _, font ) ) => match self.surface( focus ).canvas.as_ref()
{
Some( canvas ) => crate::widget::text_edit::cursor_visual_end( canvas, rect, &value, cursor, &font ),
None => value[cursor..].find( '\n' ).map( |p| cursor + p ).unwrap_or( value.len() ),
},
_ => value[cursor..].find( '\n' ).map( |p| cursor + p ).unwrap_or( value.len() ),
};
let ss = self.surface_mut( focus );
*ss.frame.cursor_state.entry( idx ).or_insert( 0 ) = new_cursor;
if !extend { *ss.frame.selection_anchor.entry( idx ).or_insert( 0 ) = new_cursor; }
ss.request_redraw();
}
}