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)
This commit is contained in:
xda 2024-10-21 21:01:49 +09:00 committed by GitHub
parent 38fc226c22
commit 14ca368be7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -131,6 +131,8 @@ pub struct TextInput {
marked_range: Option<Range<usize>>,
last_layout: Option<ShapedLine>,
last_bounds: Option<Bounds<Pixels>>,
last_cursor_offset: Option<usize>,
last_selected_range: Option<Range<usize>>,
scroll_offset: Point<Pixels>,
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);
let cursor_moved = input.last_cursor_offset != Some(cursor);
let selection_changed = input.last_selected_range != Some(selected_range.clone());
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 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;
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);