ltk/event_loop/text_editing/
scroll.rsuse crate::app::App;
use crate::event_loop::app_data::AppData;
use crate::event_loop::surface::SurfaceFocus;
use crate::tree::find_widget_at;
use crate::types::Point;
use crate::widget::text_edit::scroll::{ Scrollbar, TextScroll, Window, WHEEL_LINES };
use crate::platform::Platform;
impl<A: App, P: Platform> AppData<A, P>
{
pub( crate ) fn text_scroll( &self, focus: SurfaceFocus, idx: usize ) -> TextScroll
{
self.surface( focus ).frame.text_scroll.get( &idx ).copied().unwrap_or_default()
}
pub( crate ) fn scroll_text_under( &mut self, focus: SurfaceFocus, pos: Point, notches: f32, logical_px: f32 ) -> bool
{
let Some( idx ) = find_widget_at( &self.surface( focus ).frame.widget_rects, pos ) else { return false };
let Some( ( rect, value, true, false, _, font ) ) = self.text_input_geometry( focus, idx ) else { return false };
let ss = self.surface( focus );
let cursor_pos = ss.frame.cursor_state.get( &idx ).copied().unwrap_or( 0 );
let scroll = self.text_scroll( focus, idx );
let Some( canvas ) = ss.canvas.as_ref() else { return false };
let window = Window::shown( canvas, rect, &value, &font, cursor_pos, scroll );
let delta_px = if notches != 0.0
{
notches * WHEEL_LINES * window.metrics.line_h
} else {
logical_px * ss.scale_factor
};
if !window.can_scroll( delta_px ) { return false; }
let ( next, moved ) = scroll.scrolled( window.first_line, window.max_first, cursor_pos, delta_px, window.metrics.line_h );
let ss = self.surface_mut( focus );
ss.frame.text_scroll.insert( idx, next );
if moved { ss.request_redraw(); }
true
}
pub( crate ) fn handle_text_scrollbar_press( &mut self, focus: SurfaceFocus, idx: usize, pos: Point ) -> bool
{
self.text_scrollbar_grab = None;
let Some( ( window, bar, cursor_pos ) ) = self.text_scrollbar( focus, idx ) else { return false };
if !bar.hit.contains( pos ) { return false; }
let on_thumb = pos.y >= bar.thumb.y && pos.y <= bar.thumb.y + bar.thumb.height;
let grab = if on_thumb { pos.y - bar.thumb.y } else { bar.thumb.height / 2.0 };
self.text_scrollbar_grab = Some( ( focus, idx, grab ) );
self.scroll_text_to( focus, idx, window.first_line_for( &bar, pos.y - grab ), window.first_line, cursor_pos );
true
}
pub( crate ) fn handle_text_scrollbar_drag( &mut self, focus: SurfaceFocus, idx: usize, pos: Point ) -> bool
{
let Some( ( grab_focus, grab_idx, grab ) ) = self.text_scrollbar_grab else { return false };
if grab_focus != focus || grab_idx != idx { return false; }
if let Some( ( window, bar, cursor_pos ) ) = self.text_scrollbar( focus, idx )
{
self.scroll_text_to( focus, idx, window.first_line_for( &bar, pos.y - grab ), window.first_line, cursor_pos );
}
true
}
pub( crate ) fn text_scrollbar( &self, focus: SurfaceFocus, idx: usize ) -> Option<( Window, Scrollbar, usize )>
{
let Some( ( rect, value, true, false, _, font ) ) = self.text_input_geometry( focus, idx ) else { return None };
let ss = self.surface( focus );
let cursor_pos = ss.frame.cursor_state.get( &idx ).copied().unwrap_or( 0 );
let canvas = ss.canvas.as_ref()?;
let window = Window::shown( canvas, rect, &value, &font, cursor_pos, self.text_scroll( focus, idx ) );
let bar = window.scrollbar( canvas, rect )?;
Some( ( window, bar, cursor_pos ) )
}
fn scroll_text_to( &mut self, focus: SurfaceFocus, idx: usize, first_line: usize, shown: usize, cursor_pos: usize )
{
let ss = self.surface_mut( focus );
ss.frame.text_scroll.insert( idx, TextScroll { first_line, cursor_pos, remainder: 0.0 } );
if first_line != shown { ss.request_redraw(); }
}
}