From ed054587cd7e61283f857ab9bf82ce9935b0f5b7 Mon Sep 17 00:00:00 2001 From: rustbasic <127506429+rustbasic@users.noreply.github.com> Date: Tue, 5 Mar 2024 16:28:25 +0900 Subject: [PATCH 1/3] Update state.rs --- crates/egui/src/widgets/text_edit/state.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/egui/src/widgets/text_edit/state.rs b/crates/egui/src/widgets/text_edit/state.rs index 819688289c9..8901fd56f27 100644 --- a/crates/egui/src/widgets/text_edit/state.rs +++ b/crates/egui/src/widgets/text_edit/state.rs @@ -44,6 +44,10 @@ pub struct TextEditState { #[cfg_attr(feature = "serde", serde(skip))] pub(crate) has_ime: bool, + // cursor range for IME candidate. + #[cfg_attr(feature = "serde", serde(skip))] + pub(crate) ime_cursor_range: CursorRange, + // Visual offset when editing singleline text bigger than the width. #[cfg_attr(feature = "serde", serde(skip))] pub(crate) singleline_offset: f32, From 955476f75237f741527543d88ec17d6aff0a08e9 Mon Sep 17 00:00:00 2001 From: rustbasic <127506429+rustbasic@users.noreply.github.com> Date: Tue, 5 Mar 2024 16:28:42 +0900 Subject: [PATCH 2/3] Update builder.rs --- crates/egui/src/widgets/text_edit/builder.rs | 44 +++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/crates/egui/src/widgets/text_edit/builder.rs b/crates/egui/src/widgets/text_edit/builder.rs index 22a5623f077..ad923a7c9f5 100644 --- a/crates/egui/src/widgets/text_edit/builder.rs +++ b/crates/egui/src/widgets/text_edit/builder.rs @@ -76,6 +76,7 @@ pub struct TextEdit<'t> { desired_height_rows: usize, event_filter: EventFilter, cursor_at_end: bool, + blink: bool, min_size: Vec2, align: Align2, clip_text: bool, @@ -132,6 +133,7 @@ impl<'t> TextEdit<'t> { ..Default::default() }, cursor_at_end: true, + blink: false, min_size: Vec2::ZERO, align: Align2::LEFT_TOP, clip_text: false, @@ -305,6 +307,15 @@ impl<'t> TextEdit<'t> { self } + /// When `false` (default), the text cursor will not blink. + /// + /// When `true`, the text cursor will blink. + #[inline] + pub fn blink(mut self, b: bool) -> Self { + self.blink = b; + self + } + /// When `true` (default), overflowing text will be clipped. /// /// When `false`, widget width will expand to make all text visible. @@ -413,7 +424,7 @@ impl<'t> TextEdit<'t> { frame_rect, visuals.rounding, ui.visuals().extreme_bg_color, - visuals.bg_stroke, // TODO(emilk): we want to show something here, or a text-edit field doesn't "pop". + ui.visuals().widgets.unhovered.bg_stroke, // TODO(emilk): we want to show something here, or a text-edit field doesn't "pop". ) } } else { @@ -449,6 +460,7 @@ impl<'t> TextEdit<'t> { desired_height_rows, event_filter, cursor_at_end, + blink, min_size, align, clip_text, @@ -508,6 +520,7 @@ impl<'t> TextEdit<'t> { } }); let mut state = TextEditState::load(ui.ctx(), id).unwrap_or_default(); + let save_ccursor_range = state.cursor.char_range(); // On touch screens (e.g. mobile in `eframe` web), should // dragging select text, or scroll the enclosing [`ScrollArea`] (if any)? @@ -528,6 +541,7 @@ impl<'t> TextEdit<'t> { let mut response = ui.interact(rect, id, sense); let text_clip_rect = rect; let painter = ui.painter_at(text_clip_rect.expand(1.0)); // expand to avoid clipping cursor + let i_time = ui.input(|i| i.time); if interactive { if let Some(pointer_pos) = ui.ctx().pointer_interact_pos() { @@ -548,7 +562,10 @@ impl<'t> TextEdit<'t> { // preview: let cursor_rect = cursor_rect(response.rect.min, &galley, &cursor_at_pointer, row_height); - paint_cursor(&painter, ui.visuals(), cursor_rect); + let is_drawn = paint_cursor(&painter, ui.visuals(), cursor_rect, i_time, false); + if is_drawn { + ui.ctx().request_repaint(); + } } let is_being_dragged = ui.ctx().is_being_dragged(response.id); @@ -680,7 +697,17 @@ impl<'t> TextEdit<'t> { } if text.is_mutable() { - paint_cursor(&painter, ui.visuals(), primary_cursor_rect); + let is_blink = blink && (save_ccursor_range == state.cursor.char_range()); + let is_drawn = paint_cursor( + &painter, + ui.visuals(), + primary_cursor_rect, + i_time, + is_blink, + ); + if is_drawn { + ui.ctx().request_repaint(); + } if interactive { // For IME, so only set it when text is editable and visible! @@ -940,6 +967,7 @@ fn events( if !text_mark.is_empty() { text.insert_text_at(&mut ccursor, text_mark, char_limit); } + state.ime_cursor_range = cursor_range; Some(CCursorRange::two(start_cursor, ccursor)) } else { None @@ -947,12 +975,16 @@ fn events( } Event::CompositionEnd(prediction) => { - // CompositionEnd only characters may be typed into TextEdit without trigger CompositionStart first, so do not check `state.has_ime = true` in the following statement. + // CompositionEnd only characters may be typed into TextEdit without trigger CompositionStart first, + // so do not check `state.has_ime = true` in the following statement. if prediction != "\n" && prediction != "\r" { state.has_ime = false; - let mut ccursor = text.delete_selected(&cursor_range); - if !prediction.is_empty() { + let mut ccursor; + if !prediction.is_empty() && cursor_range == state.ime_cursor_range { + ccursor = text.delete_selected(&cursor_range); text.insert_text_at(&mut ccursor, prediction, char_limit); + } else { + ccursor = cursor_range.primary.ccursor; } Some(CCursorRange::one(ccursor)) } else { From c039e94c30ac9625528357dee43871f82d14409a Mon Sep 17 00:00:00 2001 From: rustbasic <127506429+rustbasic@users.noreply.github.com> Date: Tue, 5 Mar 2024 16:40:49 +0900 Subject: [PATCH 3/3] Update builder.rs --- crates/egui/src/widgets/text_edit/builder.rs | 33 ++------------------ 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/crates/egui/src/widgets/text_edit/builder.rs b/crates/egui/src/widgets/text_edit/builder.rs index ad923a7c9f5..12077b93292 100644 --- a/crates/egui/src/widgets/text_edit/builder.rs +++ b/crates/egui/src/widgets/text_edit/builder.rs @@ -76,7 +76,6 @@ pub struct TextEdit<'t> { desired_height_rows: usize, event_filter: EventFilter, cursor_at_end: bool, - blink: bool, min_size: Vec2, align: Align2, clip_text: bool, @@ -133,7 +132,6 @@ impl<'t> TextEdit<'t> { ..Default::default() }, cursor_at_end: true, - blink: false, min_size: Vec2::ZERO, align: Align2::LEFT_TOP, clip_text: false, @@ -307,15 +305,6 @@ impl<'t> TextEdit<'t> { self } - /// When `false` (default), the text cursor will not blink. - /// - /// When `true`, the text cursor will blink. - #[inline] - pub fn blink(mut self, b: bool) -> Self { - self.blink = b; - self - } - /// When `true` (default), overflowing text will be clipped. /// /// When `false`, widget width will expand to make all text visible. @@ -424,7 +413,7 @@ impl<'t> TextEdit<'t> { frame_rect, visuals.rounding, ui.visuals().extreme_bg_color, - ui.visuals().widgets.unhovered.bg_stroke, // TODO(emilk): we want to show something here, or a text-edit field doesn't "pop". + visuals.bg_stroke, // TODO(emilk): we want to show something here, or a text-edit field doesn't "pop". ) } } else { @@ -460,7 +449,6 @@ impl<'t> TextEdit<'t> { desired_height_rows, event_filter, cursor_at_end, - blink, min_size, align, clip_text, @@ -520,7 +508,6 @@ impl<'t> TextEdit<'t> { } }); let mut state = TextEditState::load(ui.ctx(), id).unwrap_or_default(); - let save_ccursor_range = state.cursor.char_range(); // On touch screens (e.g. mobile in `eframe` web), should // dragging select text, or scroll the enclosing [`ScrollArea`] (if any)? @@ -541,7 +528,6 @@ impl<'t> TextEdit<'t> { let mut response = ui.interact(rect, id, sense); let text_clip_rect = rect; let painter = ui.painter_at(text_clip_rect.expand(1.0)); // expand to avoid clipping cursor - let i_time = ui.input(|i| i.time); if interactive { if let Some(pointer_pos) = ui.ctx().pointer_interact_pos() { @@ -562,10 +548,7 @@ impl<'t> TextEdit<'t> { // preview: let cursor_rect = cursor_rect(response.rect.min, &galley, &cursor_at_pointer, row_height); - let is_drawn = paint_cursor(&painter, ui.visuals(), cursor_rect, i_time, false); - if is_drawn { - ui.ctx().request_repaint(); - } + paint_cursor(&painter, ui.visuals(), cursor_rect); } let is_being_dragged = ui.ctx().is_being_dragged(response.id); @@ -697,17 +680,7 @@ impl<'t> TextEdit<'t> { } if text.is_mutable() { - let is_blink = blink && (save_ccursor_range == state.cursor.char_range()); - let is_drawn = paint_cursor( - &painter, - ui.visuals(), - primary_cursor_rect, - i_time, - is_blink, - ); - if is_drawn { - ui.ctx().request_repaint(); - } + paint_cursor(&painter, ui.visuals(), primary_cursor_rect); if interactive { // For IME, so only set it when text is editable and visible!