From d22da7d261f5d5409cfe8b7bea0f80519411a5b7 Mon Sep 17 00:00:00 2001 From: dcz Date: Thu, 1 May 2025 13:03:54 +0000 Subject: [PATCH 1/4] Report `cursor` size to `InputMethod` Co-authored-by: dcz-self --- core/src/input_method.rs | 12 +++++++----- widget/src/scrollable.rs | 4 ++-- widget/src/text_editor.rs | 8 +++++--- widget/src/text_input.rs | 5 ++++- winit/src/window.rs | 22 +++++++++++++--------- 5 files changed, 31 insertions(+), 20 deletions(-) diff --git a/core/src/input_method.rs b/core/src/input_method.rs index 1d82279c..107fb27b 100644 --- a/core/src/input_method.rs +++ b/core/src/input_method.rs @@ -1,5 +1,5 @@ //! Listen to input method events. -use crate::{Pixels, Point}; +use crate::{Pixels, Rectangle}; use std::ops::Range; @@ -10,8 +10,10 @@ pub enum InputMethod { Disabled, /// Input method is enabled. Enabled { - /// The position at which the input method dialog should be placed. - position: Point, + /// The area of the cursor of the input method. + /// + /// This area should not be covered. + cursor: Rectangle, /// The [`Purpose`] of the input method. purpose: Purpose, /// The preedit to overlay on top of the input method dialog, if needed. @@ -130,11 +132,11 @@ impl InputMethod { match self { Self::Disabled => InputMethod::Disabled, Self::Enabled { - position, + cursor, purpose, preedit, } => InputMethod::Enabled { - position: *position, + cursor: *cursor, purpose: *purpose, preedit: preedit.as_ref().map(Preedit::to_owned), }, diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index a10ee771..f6999db2 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -785,10 +785,10 @@ where ); if !had_input_method - && let InputMethod::Enabled { position, .. } = + && let InputMethod::Enabled { cursor, .. } = shell.input_method_mut() { - *position = *position - translation; + *cursor = *cursor - translation; } }; diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs index 6c5efb3f..78b90e35 100644 --- a/widget/src/text_editor.rs +++ b/widget/src/text_editor.rs @@ -365,11 +365,13 @@ where self.text_size.unwrap_or_else(|| renderer.default_size()), ); - let position = - cursor + translation + Vector::new(0.0, f32::from(line_height)); + let position = cursor + translation; InputMethod::Enabled { - position, + cursor: Rectangle::new( + position, + Size::new(0.0, f32::from(line_height)), + ), purpose: input_method::Purpose::Normal, preedit: state.preedit.as_ref().map(input_method::Preedit::as_ref), } diff --git a/widget/src/text_input.rs b/widget/src/text_input.rs index 469f6c63..97ae33d1 100644 --- a/widget/src/text_input.rs +++ b/widget/src/text_input.rs @@ -428,7 +428,10 @@ where + alignment_offset; InputMethod::Enabled { - position: Point::new(x, text_bounds.y + text_bounds.height), + cursor: Rectangle::new( + Point::new(x, text_bounds.y), + Size::new(0.0, text_bounds.height), + ), purpose: if self.is_secure { input_method::Purpose::Secure } else { diff --git a/winit/src/window.rs b/winit/src/window.rs index 77274d7a..5c3b15dd 100644 --- a/winit/src/window.rs +++ b/winit/src/window.rs @@ -172,7 +172,7 @@ where pub renderer: P::Renderer, pub redraw_at: Option, preedit: Option>, - ime_state: Option<(Point, input_method::Purpose)>, + ime_state: Option<(Rectangle, input_method::Purpose)>, } impl Window @@ -215,11 +215,11 @@ where self.disable_ime(); } InputMethod::Enabled { - position, + cursor, purpose, preedit, } => { - self.enable_ime(position, purpose); + self.enable_ime(cursor, purpose); if let Some(preedit) = preedit { if preedit.content.is_empty() { @@ -229,7 +229,7 @@ where self.preedit.take().unwrap_or_else(Preedit::new); overlay.update( - position, + cursor.position(), &preedit, self.state.background_color(), &self.renderer, @@ -274,19 +274,23 @@ where } } - fn enable_ime(&mut self, position: Point, purpose: input_method::Purpose) { + fn enable_ime( + &mut self, + cursor: Rectangle, + purpose: input_method::Purpose, + ) { if self.ime_state.is_none() { self.raw.set_ime_allowed(true); } - if self.ime_state != Some((position, purpose)) { + if self.ime_state != Some((cursor, purpose)) { self.raw.set_ime_cursor_area( - LogicalPosition::new(position.x, position.y), - LogicalSize::new(10, 10), // TODO? + LogicalPosition::new(cursor.x, cursor.y), + LogicalSize::new(cursor.width, cursor.height), ); self.raw.set_ime_purpose(conversion::ime_purpose(purpose)); - self.ime_state = Some((position, purpose)); + self.ime_state = Some((cursor, purpose)); } } From 2804aff5b2e21257b4d3eef1ecc07a30c80898e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Tue, 25 Nov 2025 22:27:01 +0100 Subject: [PATCH 2/4] Set `cursor` width to `1.0` in IME requests --- widget/src/text_editor.rs | 2 +- widget/src/text_input.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs index 78b90e35..2859f568 100644 --- a/widget/src/text_editor.rs +++ b/widget/src/text_editor.rs @@ -370,7 +370,7 @@ where InputMethod::Enabled { cursor: Rectangle::new( position, - Size::new(0.0, f32::from(line_height)), + Size::new(1.0, f32::from(line_height)), ), purpose: input_method::Purpose::Normal, preedit: state.preedit.as_ref().map(input_method::Preedit::as_ref), diff --git a/widget/src/text_input.rs b/widget/src/text_input.rs index 97ae33d1..cbeefee5 100644 --- a/widget/src/text_input.rs +++ b/widget/src/text_input.rs @@ -430,7 +430,7 @@ where InputMethod::Enabled { cursor: Rectangle::new( Point::new(x, text_bounds.y), - Size::new(0.0, text_bounds.height), + Size::new(1.0, text_bounds.height), ), purpose: if self.is_secure { input_method::Purpose::Secure From 71061b53bb927deefd65a194db8ae510f5232d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Tue, 25 Nov 2025 22:37:44 +0100 Subject: [PATCH 3/4] Fix `InputMethod::merge` example in documentation --- core/src/input_method.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/input_method.rs b/core/src/input_method.rs index 107fb27b..ab19a69c 100644 --- a/core/src/input_method.rs +++ b/core/src/input_method.rs @@ -87,16 +87,16 @@ impl InputMethod { /// Merges two [`InputMethod`] strategies, prioritizing the first one when both open: /// ``` /// # use iced_core::input_method::{InputMethod, Purpose, Preedit}; - /// # use iced_core::Point; + /// # use iced_core::{Point, Rectangle, Size}; /// /// let open = InputMethod::Enabled { - /// position: Point::ORIGIN, + /// cursor: Rectangle::new(Point::ORIGIN, Size::UNIT), /// purpose: Purpose::Normal, /// preedit: Some(Preedit { content: "1".to_owned(), selection: None, text_size: None }), /// }; /// /// let open_2 = InputMethod::Enabled { - /// position: Point::ORIGIN, + /// cursor: Rectangle::new(Point::ORIGIN, Size::UNIT), /// purpose: Purpose::Secure, /// preedit: Some(Preedit { content: "2".to_owned(), selection: None, text_size: None }), /// }; From d8f12d74f8a785cbc520ea36bd39fece5d1a99e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Tue, 25 Nov 2025 22:42:11 +0100 Subject: [PATCH 4/4] Offset `Preedit` overlay by cursor height --- winit/src/window.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/winit/src/window.rs b/winit/src/window.rs index 5c3b15dd..24d63565 100644 --- a/winit/src/window.rs +++ b/winit/src/window.rs @@ -229,7 +229,7 @@ where self.preedit.take().unwrap_or_else(Preedit::new); overlay.update( - cursor.position(), + cursor, &preedit, self.state.background_color(), &self.renderer, @@ -357,12 +357,12 @@ where fn update( &mut self, - position: Point, + cursor: Rectangle, preedit: &input_method::Preedit, background: Color, renderer: &Renderer, ) { - self.position = position; + self.position = cursor.position() + Vector::new(0.0, cursor.height); let background = Color { a: 1.0,