Hide Android selection handles when scrolled out of view

In a LineEdit with a long text, when dragging the selection
to the point where the anchor scrolls out of view in the other
direection, it used to keep being visible, outside the LineEdit.

This commit fixes that by passing the clip rect to the java code
that positions the selection handles.
This commit is contained in:
David Faure 2025-09-14 01:29:41 +02:00 committed by Olivier Goffart
parent 92ebe92f62
commit b23a657c44
4 changed files with 43 additions and 13 deletions

View file

@ -243,18 +243,31 @@ class SlintInputView extends View {
mCursorHandle.setPosition(left_x, left_y);
handleHeight = mCursorHandle.getHeight();
} else if (num_handles == 2) {
if (left_x != -1) {
if (mLeftHandle == null) {
mLeftHandle = new InputHandle(this, android.R.attr.textSelectHandleLeft);
}
mLeftHandle.setPosition(left_x, left_y);
handleHeight = mLeftHandle.getHeight();
} else {
if (mLeftHandle != null) {
mLeftHandle.hide();
}
}
if (right_x != -1) {
if (mRightHandle == null) {
mRightHandle = new InputHandle(this, android.R.attr.textSelectHandleRight);
}
mRightHandle.setPosition(right_x, right_y);
handleHeight = mRightHandle.getHeight();
} else {
if (mRightHandle != null) {
mRightHandle.hide();
}
}
if (mCursorHandle != null) {
mCursorHandle.hide();
}
mLeftHandle.setPosition(left_x, left_y);
mRightHandle.setPosition(right_x, right_y);
handleHeight = mLeftHandle.getHeight();
showActionMenu();
} else {
if (mCursorHandle != null) {

View file

@ -194,15 +194,22 @@ impl JavaHelper {
};
env.delete_local_ref(class_it)?;
let cur_origin = data.cursor_rect_origin.to_physical(scale_factor);
let cur_origin = data.cursor_rect_origin.to_physical(scale_factor); // i32
let anchor_origin = data.anchor_point.to_physical(scale_factor);
let cur_size = data.cursor_rect_size.to_physical(scale_factor);
let cur_visible = data.clip_rect.map_or(true, |r| {
r.contains(i_slint_core::lengths::logical_point_from_api(data.cursor_rect_origin))
});
let anchor_visible = data.clip_rect.map_or(true, |r| {
r.contains(i_slint_core::lengths::logical_point_from_api(data.anchor_point))
});
// Add 2*cur_size.width to the y position to be a bit under the cursor
let cursor_height = cur_size.height as i32 + 2 * cur_size.width as i32;
let cur_x = cur_origin.x + cur_size.width as i32 / 2;
let cur_x = if cur_visible { cur_origin.x + cur_size.width as i32 / 2 } else { -1 };
let cur_y = cur_origin.y + cursor_height;
let anchor_x = anchor_origin.x;
let anchor_x = if anchor_visible { anchor_origin.x } else { -1 };
let anchor_y = anchor_origin.y + 2 * cur_size.width as i32;
env.call_method(

View file

@ -1505,15 +1505,22 @@ impl TextInput {
let cursor_relative =
self.cursor_rect_for_byte_offset(cursor_position, window_adapter, self_rc);
let geometry = self_rc.geometry();
let origin = self_rc.map_to_window(geometry.origin).to_vector();
let origin = self_rc.map_to_window(geometry.origin);
let origin_vector = origin.to_vector();
let cursor_rect_origin =
crate::api::LogicalPosition::from_euclid(cursor_relative.origin + origin);
crate::api::LogicalPosition::from_euclid(cursor_relative.origin + origin_vector);
let cursor_rect_size = crate::api::LogicalSize::from_euclid(cursor_relative.size);
let anchor_point = crate::api::LogicalPosition::from_euclid(
self.cursor_rect_for_byte_offset(anchor_position, window_adapter, self_rc).origin
+ origin
+ origin_vector
+ cursor_relative.size,
);
let maybe_parent =
self_rc.parent_item(crate::item_tree::ParentItemTraversalMode::StopAtPopups);
let clip_rect = maybe_parent.map(|parent| {
let geom = parent.geometry();
LogicalRect::new(parent.map_to_window(geom.origin), geom.size)
});
InputMethodProperties {
text,
@ -1525,6 +1532,7 @@ impl TextInput {
cursor_rect_size,
anchor_point,
input_type: self.input_type(),
clip_rect,
}
}

View file

@ -293,6 +293,8 @@ pub struct InputMethodProperties {
pub anchor_point: LogicalPosition,
/// The type of input for the text edit.
pub input_type: InputType,
/// The clip rect in window coordinates
pub clip_rect: Option<LogicalRect>,
}
/// This struct describes layout constraints of a resizable element, such as a window.