/// Compute the result of movement on a selection.
///
/// returns a new selection representing the state after the movement.
///
/// If `modify` is true, only the 'active' edge (the `end`) of the selection
/// should be changed; this is the case when the user moves with the shift
/// key pressed.
Compute the result of movement on a selection.
returns a new selection representing the state after the movement.

If `modify` is true, only the 'active' edge (the `end`) of the selection
should be changed; this is the case when the user moves with the shift
key pressed.
Compute the result of movement on a selection . returns a new selection representing the state after the movement . If ` modify ` is true only the ' active ' edge ( the ` end ` ) of the selection should be changed ; this is the case when the user moves with the shift key pressed .
pub fn movement<T: EditableText + TextStorage>(
    m: Movement,
    s: Selection,
    layout: &TextLayout<T>,
    modify: bool,
) -> Selection {
    let (text, layout) = match (layout.text(), layout.layout()) {
        (Some(text), Some(layout)) => (text, layout),
        _ => {
            debug_assert!(false, "movement() called before layout rebuild");
            return s;
        }
    };
    let writing_direction = if crate::piet::util::first_strong_rtl(text.as_str()) {
        WritingDirection::RightToLeft
    } else {
        WritingDirection::LeftToRight
    };
    let (offset, h_pos) = match m {
        Movement::Grapheme(d) if d.is_upstream_for_direction(writing_direction) => {
            if s.is_caret() || modify {
                text.prev_grapheme_offset(s.active)
                    .map(|off| (off, None))
                    .unwrap_or((0, s.h_pos))
            } else {
                (s.min(), None)
            }
        }
        Movement::Grapheme(_) => {
            if s.is_caret() || modify {
                text.next_grapheme_offset(s.active)
                    .map(|off| (off, None))
                    .unwrap_or((s.active, s.h_pos))
            } else {
                (s.max(), None)
            }
        }
        Movement::Vertical(VerticalMovement::LineUp) => {
            let cur_pos = layout.hit_test_text_position(s.active);
            let h_pos = s.h_pos.unwrap_or(cur_pos.point.x);
            if cur_pos.line == 0 {
                (0, Some(h_pos))
            } else {
                let lm = layout.line_metric(cur_pos.line).unwrap();
                let point_above = Point::new(h_pos, cur_pos.point.y - lm.height);
                let up_pos = layout.hit_test_point(point_above);
                (up_pos.idx, Some(point_above.x))
            }
        }
        Movement::Vertical(VerticalMovement::LineDown) => {
            let cur_pos = layout.hit_test_text_position(s.active);
            let h_pos = s.h_pos.unwrap_or(cur_pos.point.x);
            if cur_pos.line == layout.line_count() - 1 {
                (text.len(), Some(h_pos))
            } else {
                let lm = layout.line_metric(cur_pos.line).unwrap();
                // may not work correctly for point sizes below 1.0
                let y_below = lm.y_offset + lm.height + 1.0;
                let point_below = Point::new(h_pos, y_below);
                let up_pos = layout.hit_test_point(point_below);
                (up_pos.idx, Some(point_below.x))
            }
        }
        Movement::Vertical(VerticalMovement::DocumentStart) => (0, None),
        Movement::Vertical(VerticalMovement::DocumentEnd) => (text.len(), None),
        Movement::ParagraphStart => (text.preceding_line_break(s.active), None),
        Movement::ParagraphEnd => (text.next_line_break(s.active), None),
        Movement::Line(d) => {
            let hit = layout.hit_test_text_position(s.active);
            let lm = layout.line_metric(hit.line).unwrap();
            let offset = if d.is_upstream_for_direction(writing_direction) {
                lm.start_offset
            } else {
                lm.end_offset
            };
            (offset, None)
        }
        Movement::Word(d) if d.is_upstream_for_direction(writing_direction) => {
            let offset = if s.is_caret() || modify {
                text.prev_word_offset(s.active).unwrap_or(0)
            } else {
                s.min()
            };
            (offset, None)
        }
        Movement::Word(_) => {
            let offset = if s.is_caret() || modify {
                text.next_word_offset(s.active).unwrap_or(s.active)
            } else {
                s.max()
            };
            (offset, None)
        }
        // These two are not handled; they require knowledge of the size
        // of the viewport.
        Movement::Vertical(VerticalMovement::PageDown)
        | Movement::Vertical(VerticalMovement::PageUp) => (s.active, s.h_pos),
        other => {
            tracing::warn!("unhandled movement {:?}", other);
            (s.anchor, s.h_pos)
        }
    };
    let start = if modify { s.anchor } else { offset };
    Selection::new(start, offset).with_h_pos(h_pos)
}
pub fn movement < T : EditableText + TextStorage > ( m : Movement , s : Selection , layout : & TextLayout < T > , modify : bool , ) -> Selection { let ( text , layout ) = match ( layout . text ( ) , layout . layout ( ) ) { ( Some ( text ) , Some ( layout ) ) => ( text , layout ) , _ => { debug_assert ! ( false " " ) ; return s ; } } ; let writing_direction = if crate :: piet :: util :: first_strong_rtl ( text . as_str ( ) ) { WritingDirection :: RightToLeft } else { WritingDirection :: LeftToRight } ; let ( offset , h_pos ) = match m { Movement :: Grapheme ( d ) if d . is_upstream_for_direction ( writing_direction ) => { if s . is_caret ( ) || modify { text . prev_grapheme_offset ( s . active ) . map ( | off | ( off , None ) ) . unwrap_or ( ( 0 , s . h_pos ) ) } else { ( s . min ( ) , None ) } } Movement :: Grapheme ( _ ) => { if s . is_caret ( ) || modify { text . next_grapheme_offset ( s . active ) . map ( | off | ( off , None ) ) . unwrap_or ( ( s . active , s . h_pos ) ) } else { ( s . max ( ) , None ) } } Movement :: Vertical ( VerticalMovement :: LineUp ) => { let cur_pos = layout . hit_test_text_position ( s . active ) ; let h_pos = s . h_pos . unwrap_or ( cur_pos . point . x ) ; if cur_pos . line == 0 { ( 0 , Some ( h_pos ) ) } else { let lm = layout . line_metric ( cur_pos . line ) . unwrap ( ) ; let point_above = Point :: new ( h_pos , cur_pos . point . y - lm . height ) ; let up_pos = layout . hit_test_point ( point_above ) ; ( up_pos . idx , Some ( point_above . x ) ) } } Movement :: Vertical ( VerticalMovement :: LineDown ) => { let cur_pos = layout . hit_test_text_position ( s . active ) ; let h_pos = s . h_pos . unwrap_or ( cur_pos . point . x ) ; if cur_pos . line == layout . line_count ( ) - 1 { ( text . len ( ) , Some ( h_pos ) ) } else { let lm = layout . line_metric ( cur_pos . line ) . unwrap ( ) ; // may not work correctly for point sizes below 1.0 let y_below = lm . y_offset + lm . height + 1.0 ; let point_below = Point :: new ( h_pos , y_below ) ; let up_pos = layout . hit_test_point ( point_below ) ; ( up_pos . idx , Some ( point_below . x ) ) } } Movement :: Vertical ( VerticalMovement :: DocumentStart ) => ( 0 , None ) , Movement :: Vertical ( VerticalMovement :: DocumentEnd ) => ( text . len ( ) , None ) , Movement :: ParagraphStart => ( text . preceding_line_break ( s . active ) , None ) , Movement :: ParagraphEnd => ( text . next_line_break ( s . active ) , None ) , Movement :: Line ( d ) => { let hit = layout . hit_test_text_position ( s . active ) ; let lm = layout . line_metric ( hit . line ) . unwrap ( ) ; let offset = if d . is_upstream_for_direction ( writing_direction ) { lm . start_offset } else { lm . end_offset } ; ( offset , None ) } Movement :: Word ( d ) if d . is_upstream_for_direction ( writing_direction ) => { let offset = if s . is_caret ( ) || modify { text . prev_word_offset ( s . active ) . unwrap_or ( 0 ) } else { s . min ( ) } ; ( offset , None ) } Movement :: Word ( _ ) => { let offset = if s . is_caret ( ) || modify { text . next_word_offset ( s . active ) . unwrap_or ( s . active ) } else { s . max ( ) } ; ( offset , None ) } // These two are not handled; they require knowledge of the size // of the viewport. Movement :: Vertical ( VerticalMovement :: PageDown ) | Movement :: Vertical ( VerticalMovement :: PageUp ) => ( s . active , s . h_pos ) , other => { tracing :: warn ! ( " " other ) ; ( s . anchor , s . h_pos ) } } ; let start = if modify { s . anchor } else { offset } ; Selection :: new ( start , offset ) . with_h_pos ( h_pos ) }
Compute the result of movement on a selection.
Compute the result of movement on a selection .
m
Movement
s
Selection
layout
&TextLayout<T>
modify
bool