From 14ca368be75a25211f672f3a3365871887440d95 Mon Sep 17 00:00:00 2001 From: xda <150917089+xda2023@users.noreply.github.com> Date: Mon, 21 Oct 2024 21:01:49 +0900 Subject: [PATCH] input: Ensure resizing the window doesn't force the cursor back into view (#370) Fix #331 It is ensured that the scroll offset remains consistent during parent container resizing, preventing the cursor from being forced back into view unless the user interacts with the input, providing a more consistent user experience in scenarios where automatic scrolling during resizing is undesirable. This behavior aligns with common text editors and input fields where resizing the window doesn't force the cursor back into view. ![2024-10-21 20 27 00](https://github.com/user-attachments/assets/599ef72d-3ec8-4fe5-a26c-10263044db6f) --- crates/ui/src/input/input.rs | 52 ++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/crates/ui/src/input/input.rs b/crates/ui/src/input/input.rs index 7ac7f8b4..cef18677 100644 --- a/crates/ui/src/input/input.rs +++ b/crates/ui/src/input/input.rs @@ -131,6 +131,8 @@ pub struct TextInput { marked_range: Option>, last_layout: Option, last_bounds: Option>, + last_cursor_offset: Option, + last_selected_range: Option>, scroll_offset: Point, is_selecting: bool, disabled: bool, @@ -160,6 +162,8 @@ impl TextInput { marked_range: None, last_layout: None, last_bounds: None, + last_cursor_offset: None, + last_selected_range: None, scroll_offset: point(px(0.), px(0.)), is_selecting: false, disabled: false, @@ -975,26 +979,30 @@ impl Element for TextElement { let cursor_pos = line.x_for_index(cursor); let cursor_start = line.x_for_index(selected_range.start); let cursor_end = line.x_for_index(selected_range.end); - - scroll_offset.x = if scroll_offset.x + cursor_pos > (bounds.size.width - right_margin) { - // cursor is out of right - bounds.size.width - right_margin - cursor_pos - } else if scroll_offset.x + cursor_pos < px(0.) { - // cursor is out of left - scroll_offset.x - cursor_pos - } else { - scroll_offset.x - }; - - if input.selection_reversed { - if scroll_offset.x + cursor_start < px(0.) { - // selection start is out of left - scroll_offset.x = -cursor_start; - } - } else { - if scroll_offset.x + cursor_end <= px(0.) { - // selection end is out of left - scroll_offset.x = -cursor_end; + let cursor_moved = input.last_cursor_offset != Some(cursor); + let selection_changed = input.last_selected_range != Some(selected_range.clone()); + + if cursor_moved || selection_changed { + scroll_offset.x = if scroll_offset.x + cursor_pos > (bounds.size.width - right_margin) { + // cursor is out of right + bounds.size.width - right_margin - cursor_pos + } else if scroll_offset.x + cursor_pos < px(0.) { + // cursor is out of left + scroll_offset.x - cursor_pos + } else { + scroll_offset.x + }; + + if input.selection_reversed { + if scroll_offset.x + cursor_start < px(0.) { + // selection start is out of left + scroll_offset.x = -cursor_start; + } + } else { + if scroll_offset.x + cursor_end <= px(0.) { + // selection end is out of left + scroll_offset.x = -cursor_end; + } } } @@ -1053,6 +1061,8 @@ impl Element for TextElement { let focus_handle = self.input.read(cx).focus_handle.clone(); let focused = focus_handle.is_focused(cx); let bounds = prepaint.bounds; + let selected_range = self.input.read(cx).selected_range.clone(); + let cursor = self.input.read(cx).cursor_offset(); cx.handle_input( &focus_handle, @@ -1073,6 +1083,8 @@ impl Element for TextElement { input.scroll_offset = prepaint.scroll_offset; input.last_layout = Some(line); input.last_bounds = Some(bounds); + input.last_cursor_offset = Some(cursor); + input.last_selected_range = Some(selected_range); }); self.paint_mouse_listeners(cx);