Fix cursor positioning in TextInput
on overflow
This commit is contained in:
parent
453d2d5bb0
commit
36e7ac2048
@ -93,6 +93,16 @@ impl text_input::Renderer for Null {
|
||||
0.0
|
||||
}
|
||||
|
||||
fn offset(
|
||||
&self,
|
||||
_text_bounds: Rectangle,
|
||||
_size: u16,
|
||||
_value: &text_input::Value,
|
||||
_state: &text_input::State,
|
||||
) -> f32 {
|
||||
0.0
|
||||
}
|
||||
|
||||
fn draw(
|
||||
&mut self,
|
||||
_bounds: Rectangle,
|
||||
|
@ -179,35 +179,40 @@ where
|
||||
button: mouse::Button::Left,
|
||||
state: ButtonState::Pressed,
|
||||
}) => {
|
||||
self.state.is_focused =
|
||||
layout.bounds().contains(cursor_position);
|
||||
let is_clicked = layout.bounds().contains(cursor_position);
|
||||
|
||||
if self.state.is_focused {
|
||||
if is_clicked {
|
||||
let text_layout = layout.children().next().unwrap();
|
||||
let target = cursor_position.x - text_layout.bounds().x;
|
||||
|
||||
if target < 0.0 {
|
||||
self.state.cursor_position = 0;
|
||||
} else if self.is_secure {
|
||||
self.state.cursor_position = find_cursor_position(
|
||||
renderer,
|
||||
target,
|
||||
&self.value.secure(),
|
||||
self.size.unwrap_or(renderer.default_size()),
|
||||
0,
|
||||
self.value.len(),
|
||||
if target > 0.0 {
|
||||
let value = if self.is_secure {
|
||||
self.value.secure()
|
||||
} else {
|
||||
self.value.clone()
|
||||
};
|
||||
|
||||
let size = self.size.unwrap_or(renderer.default_size());
|
||||
|
||||
let offset = renderer.offset(
|
||||
text_layout.bounds(),
|
||||
size,
|
||||
&value,
|
||||
&self.state,
|
||||
);
|
||||
} else {
|
||||
|
||||
self.state.cursor_position = find_cursor_position(
|
||||
renderer,
|
||||
target,
|
||||
&self.value,
|
||||
self.size.unwrap_or(renderer.default_size()),
|
||||
target + offset,
|
||||
&value,
|
||||
size,
|
||||
0,
|
||||
self.value.len(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.state.is_focused = is_clicked;
|
||||
}
|
||||
Event::Keyboard(keyboard::Event::CharacterReceived(c))
|
||||
if self.state.is_focused
|
||||
@ -392,6 +397,22 @@ pub trait Renderer: crate::Renderer + Sized {
|
||||
/// [`TextInput`]: struct.TextInput.html
|
||||
fn measure_value(&self, value: &str, size: u16) -> f32;
|
||||
|
||||
/// Returns the current horizontal offset of the value of the
|
||||
/// [`TextInput`].
|
||||
///
|
||||
/// This is the amount of horizontal scrolling applied when the [`Value`]
|
||||
/// does not fit the [`TextInput`].
|
||||
///
|
||||
/// [`TextInput`]: struct.TextInput.html
|
||||
/// [`Value`]: struct.Value.html
|
||||
fn offset(
|
||||
&self,
|
||||
text_bounds: Rectangle,
|
||||
size: u16,
|
||||
value: &Value,
|
||||
state: &State,
|
||||
) -> f32;
|
||||
|
||||
/// Draws a [`TextInput`].
|
||||
///
|
||||
/// It receives:
|
||||
|
@ -30,6 +30,28 @@ impl text_input::Renderer for Renderer {
|
||||
width
|
||||
}
|
||||
|
||||
fn offset(
|
||||
&self,
|
||||
text_bounds: Rectangle,
|
||||
size: u16,
|
||||
value: &text_input::Value,
|
||||
state: &text_input::State,
|
||||
) -> f32 {
|
||||
if state.is_focused() {
|
||||
let (_, offset) = measure_cursor_and_scroll_offset(
|
||||
self,
|
||||
text_bounds,
|
||||
value,
|
||||
size,
|
||||
state.cursor_position(value),
|
||||
);
|
||||
|
||||
offset
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(
|
||||
&mut self,
|
||||
bounds: Rectangle,
|
||||
@ -91,11 +113,13 @@ impl text_input::Renderer for Renderer {
|
||||
};
|
||||
|
||||
let (contents_primitive, offset) = if state.is_focused() {
|
||||
let text_before_cursor =
|
||||
value.until(state.cursor_position(value)).to_string();
|
||||
|
||||
let text_value_width =
|
||||
self.measure_value(&text_before_cursor, size);
|
||||
let (text_value_width, offset) = measure_cursor_and_scroll_offset(
|
||||
self,
|
||||
text_bounds,
|
||||
value,
|
||||
size,
|
||||
state.cursor_position(value),
|
||||
);
|
||||
|
||||
let cursor = Primitive::Quad {
|
||||
bounds: Rectangle {
|
||||
@ -112,11 +136,7 @@ impl text_input::Renderer for Renderer {
|
||||
Primitive::Group {
|
||||
primitives: vec![text_value, cursor],
|
||||
},
|
||||
Vector::new(
|
||||
((text_value_width + 5.0) - text_bounds.width).max(0.0)
|
||||
as u32,
|
||||
0,
|
||||
),
|
||||
Vector::new(offset as u32, 0),
|
||||
)
|
||||
} else {
|
||||
(text_value, Vector::new(0, 0))
|
||||
@ -140,3 +160,20 @@ impl text_input::Renderer for Renderer {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn measure_cursor_and_scroll_offset(
|
||||
renderer: &Renderer,
|
||||
text_bounds: Rectangle,
|
||||
value: &text_input::Value,
|
||||
size: u16,
|
||||
cursor_index: usize,
|
||||
) -> (f32, f32) {
|
||||
use iced_native::text_input::Renderer;
|
||||
|
||||
let text_before_cursor = value.until(cursor_index).to_string();
|
||||
|
||||
let text_value_width = renderer.measure_value(&text_before_cursor, size);
|
||||
let offset = ((text_value_width + 5.0) - text_bounds.width).max(0.0);
|
||||
|
||||
(text_value_width, offset)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user