diff --git a/crates/egui/src/data/output.rs b/crates/egui/src/data/output.rs index e90f99adf55e..57bbae310894 100644 --- a/crates/egui/src/data/output.rs +++ b/crates/egui/src/data/output.rs @@ -435,8 +435,8 @@ pub struct WidgetInfo { /// The current value of sliders etc. pub value: Option, - /// The current text selection, for a focused text edit. - pub text_selection: Option, + /// Selected range of characters in [`Self::current_text_value`]. + pub text_selection: Option>, } impl std::fmt::Debug for WidgetInfo { @@ -530,11 +530,7 @@ impl WidgetInfo { } #[allow(clippy::needless_pass_by_value)] - pub fn text_edit( - text_selection: Option, - prev_text_value: impl ToString, - text_value: impl ToString, - ) -> Self { + pub fn text_edit(prev_text_value: impl ToString, text_value: impl ToString) -> Self { let text_value = text_value.to_string(); let prev_text_value = prev_text_value.to_string(); let prev_text_value = if text_value == prev_text_value { @@ -543,13 +539,24 @@ impl WidgetInfo { Some(prev_text_value) }; Self { - text_selection, current_text_value: Some(text_value), prev_text_value, ..Self::new(WidgetType::TextEdit) } } + #[allow(clippy::needless_pass_by_value)] + pub fn text_selection_changed( + text_selection: std::ops::RangeInclusive, + current_text_value: impl ToString, + ) -> Self { + Self { + text_selection: Some(text_selection), + current_text_value: Some(current_text_value.to_string()), + ..Self::new(WidgetType::TextEdit) + } + } + /// This can be used by a text-to-speech system to describe the widget. pub fn description(&self) -> String { let Self { diff --git a/crates/egui/src/widgets/text_edit/builder.rs b/crates/egui/src/widgets/text_edit/builder.rs index ae4f6d7cf4b4..d4a30c2c1cd2 100644 --- a/crates/egui/src/widgets/text_edit/builder.rs +++ b/crates/egui/src/widgets/text_edit/builder.rs @@ -633,18 +633,29 @@ impl<'t> TextEdit<'t> { state.clone().store(ui.ctx(), id); - let make_info = || { - WidgetInfo::text_edit( - cursor_range, - mask_if_password(password, prev_text.as_str()), + if response.changed { + response.widget_info(|| { + WidgetInfo::text_edit( + mask_if_password(password, prev_text.as_str()), + mask_if_password(password, text.as_str()), + ) + }); + } else if selection_changed { + let cursor_range = cursor_range.unwrap(); + let char_range = + cursor_range.primary.ccursor.index..=cursor_range.secondary.ccursor.index; + let info = WidgetInfo::text_selection_changed( + char_range, mask_if_password(password, text.as_str()), - ) - }; - - if selection_changed && !response.changed { - response.output_event(OutputEvent::TextSelectionChanged(make_info())); + ); + response.output_event(OutputEvent::TextSelectionChanged(info)); } else { - response.widget_info(make_info); + response.widget_info(|| { + WidgetInfo::text_edit( + mask_if_password(password, prev_text.as_str()), + mask_if_password(password, text.as_str()), + ) + }); } #[cfg(feature = "accesskit")]