summaryrefslogtreecommitdiffstats
path: root/widget/src/text_input.rs
diff options
context:
space:
mode:
Diffstat (limited to 'widget/src/text_input.rs')
-rw-r--r--widget/src/text_input.rs95
1 files changed, 93 insertions, 2 deletions
diff --git a/widget/src/text_input.rs b/widget/src/text_input.rs
index 57ebe46a..f2756b5b 100644
--- a/widget/src/text_input.rs
+++ b/widget/src/text_input.rs
@@ -36,6 +36,7 @@ mod value;
pub mod cursor;
pub use cursor::Cursor;
+use iced_runtime::core::input_method;
pub use value::Value;
use editor::Editor;
@@ -56,8 +57,8 @@ use crate::core::widget::operation::{self, Operation};
use crate::core::widget::tree::{self, Tree};
use crate::core::window;
use crate::core::{
- Background, Border, Color, Element, Event, Layout, Length, Padding, Pixels,
- Point, Rectangle, Shell, Size, Theme, Vector, Widget,
+ Background, Border, CaretInfo, Color, Element, Event, Layout, Length,
+ Padding, Pixels, Point, Rectangle, Shell, Size, Theme, Vector, Widget,
};
use crate::runtime::task::{self, Task};
use crate::runtime::Action;
@@ -391,6 +392,58 @@ where
}
}
+ fn caret_rect(
+ &self,
+ tree: &Tree,
+ layout: Layout<'_>,
+ value: Option<&Value>,
+ ) -> Option<Rectangle> {
+ let state = tree.state.downcast_ref::<State<Renderer::Paragraph>>();
+ let value = value.unwrap_or(&self.value);
+
+ let secure_value = self.is_secure.then(|| value.secure());
+ let value = secure_value.as_ref().unwrap_or(value);
+
+ let mut children_layout = layout.children();
+ let text_bounds = children_layout.next().unwrap().bounds();
+
+ if let Some(_) = state
+ .is_focused
+ .as_ref()
+ .filter(|focus| focus.is_window_focused)
+ {
+ let caret_index = match state.cursor.state(value) {
+ cursor::State::Index(position) => position,
+ cursor::State::Selection { start, end } => {
+ let left = start.min(end);
+ left
+ }
+ };
+ let text = state.value.raw();
+ let (caret_x, offset) = measure_cursor_and_scroll_offset(
+ text,
+ text_bounds,
+ caret_index,
+ );
+
+ let alignment_offset = alignment_offset(
+ text_bounds.width,
+ text.min_width(),
+ self.alignment,
+ );
+
+ let x = (text_bounds.x + caret_x).floor();
+ Some(Rectangle {
+ x: (alignment_offset - offset) + x,
+ y: text_bounds.y,
+ width: 1.0,
+ height: text_bounds.height,
+ })
+ } else {
+ None
+ }
+ }
+
/// Draws the [`TextInput`] with the given [`Renderer`], overriding its
/// [`Value`] if provided.
///
@@ -1197,6 +1250,31 @@ where
state.keyboard_modifiers = *modifiers;
}
+ Event::InputMethod(input_method::Event::Commit(string)) => {
+ let state = state::<Renderer>(tree);
+
+ if let Some(focus) = &mut state.is_focused {
+ let Some(on_input) = &self.on_input else {
+ return;
+ };
+
+ state.is_pasting = None;
+
+ let mut editor =
+ Editor::new(&mut self.value, &mut state.cursor);
+
+ editor.paste(Value::new(&string));
+
+ let message = (on_input)(editor.contents());
+ shell.publish(message);
+
+ focus.updated_at = Instant::now();
+
+ update_cache(state, &self.value);
+
+ shell.capture_event();
+ }
+ }
Event::Window(window::Event::Unfocused) => {
let state = state::<Renderer>(tree);
@@ -1256,6 +1334,19 @@ where
Status::Active
};
+ shell.update_caret_info(if state.is_focused() {
+ let rect = self
+ .caret_rect(tree, layout, Some(&self.value))
+ .unwrap_or(Rectangle::with_size(Size::<f32>::default()));
+ let bottom_left = Point::new(rect.x, rect.y + rect.height);
+ Some(CaretInfo {
+ position: bottom_left,
+ input_method_allowed: true,
+ })
+ } else {
+ None
+ });
+
if let Event::Window(window::Event::RedrawRequested(_now)) = event {
self.last_status = Some(status);
} else if self