Add support for reporting cursor selection changes.
This commit is contained in:
parent
97aa56f465
commit
2433506c92
4 changed files with 61 additions and 3 deletions
|
@ -194,6 +194,7 @@ impl CtxRef {
|
||||||
is_pointer_button_down_on: false,
|
is_pointer_button_down_on: false,
|
||||||
interact_pointer_pos: None,
|
interact_pointer_pos: None,
|
||||||
changed: false, // must be set by the widget itself
|
changed: false, // must be set by the widget itself
|
||||||
|
has_widget_info: false, // must be set by the widget itself
|
||||||
};
|
};
|
||||||
|
|
||||||
if !enabled || !sense.focusable || !layer_id.allow_interaction() {
|
if !enabled || !sense.focusable || !layer_id.allow_interaction() {
|
||||||
|
|
|
@ -43,6 +43,7 @@ impl Output {
|
||||||
OutputEvent::Clicked(widget_info)
|
OutputEvent::Clicked(widget_info)
|
||||||
| OutputEvent::DoubleClicked(widget_info)
|
| OutputEvent::DoubleClicked(widget_info)
|
||||||
| OutputEvent::FocusGained(widget_info)
|
| OutputEvent::FocusGained(widget_info)
|
||||||
|
| OutputEvent::TextSelectionChanged(widget_info)
|
||||||
| OutputEvent::ValueChanged(widget_info) => {
|
| OutputEvent::ValueChanged(widget_info) => {
|
||||||
return widget_info.description();
|
return widget_info.description();
|
||||||
}
|
}
|
||||||
|
@ -213,6 +214,8 @@ pub enum OutputEvent {
|
||||||
DoubleClicked(WidgetInfo),
|
DoubleClicked(WidgetInfo),
|
||||||
/// A widget gained keyboard focus (by tab key).
|
/// A widget gained keyboard focus (by tab key).
|
||||||
FocusGained(WidgetInfo),
|
FocusGained(WidgetInfo),
|
||||||
|
// Text selection was updated.
|
||||||
|
TextSelectionChanged(WidgetInfo),
|
||||||
// A widget's value changed.
|
// A widget's value changed.
|
||||||
ValueChanged(WidgetInfo),
|
ValueChanged(WidgetInfo),
|
||||||
}
|
}
|
||||||
|
@ -223,6 +226,7 @@ impl std::fmt::Debug for OutputEvent {
|
||||||
Self::Clicked(wi) => write!(f, "Clicked({:?})", wi),
|
Self::Clicked(wi) => write!(f, "Clicked({:?})", wi),
|
||||||
Self::DoubleClicked(wi) => write!(f, "DoubleClicked({:?})", wi),
|
Self::DoubleClicked(wi) => write!(f, "DoubleClicked({:?})", wi),
|
||||||
Self::FocusGained(wi) => write!(f, "FocusGained({:?})", wi),
|
Self::FocusGained(wi) => write!(f, "FocusGained({:?})", wi),
|
||||||
|
Self::TextSelectionChanged(wi) => write!(f, "TextSelectionChanged({:?})", wi),
|
||||||
Self::ValueChanged(wi) => write!(f, "ValueChanged({:?})", wi),
|
Self::ValueChanged(wi) => write!(f, "ValueChanged({:?})", wi),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -238,11 +242,15 @@ pub struct WidgetInfo {
|
||||||
/// The contents of some editable text (for `TextEdit` fields).
|
/// The contents of some editable text (for `TextEdit` fields).
|
||||||
pub text_value: Option<String>,
|
pub text_value: Option<String>,
|
||||||
// The previous text value.
|
// The previous text value.
|
||||||
prev_text_value: Option<String>,
|
pub prev_text_value: Option<String>,
|
||||||
/// The current value of checkboxes and radio buttons.
|
/// The current value of checkboxes and radio buttons.
|
||||||
pub selected: Option<bool>,
|
pub selected: Option<bool>,
|
||||||
/// The current value of sliders etc.
|
/// The current value of sliders etc.
|
||||||
pub value: Option<f64>,
|
pub value: Option<f64>,
|
||||||
|
// Location of primary cursor.
|
||||||
|
pub primary_cursor: Option<usize>,
|
||||||
|
// Location of secondary cursor.
|
||||||
|
pub secondary_cursor: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for WidgetInfo {
|
impl std::fmt::Debug for WidgetInfo {
|
||||||
|
@ -254,6 +262,8 @@ impl std::fmt::Debug for WidgetInfo {
|
||||||
prev_text_value,
|
prev_text_value,
|
||||||
selected,
|
selected,
|
||||||
value,
|
value,
|
||||||
|
primary_cursor,
|
||||||
|
secondary_cursor,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let mut s = f.debug_struct("WidgetInfo");
|
let mut s = f.debug_struct("WidgetInfo");
|
||||||
|
@ -275,6 +285,12 @@ impl std::fmt::Debug for WidgetInfo {
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
s.field("value", value);
|
s.field("value", value);
|
||||||
}
|
}
|
||||||
|
if let Some(primary_cursor) = primary_cursor {
|
||||||
|
s.field("primary_cursor", primary_cursor);
|
||||||
|
}
|
||||||
|
if let Some(secondary_cursor) = secondary_cursor {
|
||||||
|
s.field("secondary_cursor", secondary_cursor);
|
||||||
|
}
|
||||||
|
|
||||||
s.finish()
|
s.finish()
|
||||||
}
|
}
|
||||||
|
@ -289,6 +305,8 @@ impl WidgetInfo {
|
||||||
prev_text_value: None,
|
prev_text_value: None,
|
||||||
selected: None,
|
selected: None,
|
||||||
value: None,
|
value: None,
|
||||||
|
primary_cursor: None,
|
||||||
|
secondary_cursor: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,6 +354,20 @@ impl WidgetInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::needless_pass_by_value)]
|
||||||
|
pub fn text_selection_changed(
|
||||||
|
primary_cursor: usize,
|
||||||
|
secondary_cursor: usize,
|
||||||
|
text_value: impl ToString,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
primary_cursor: Some(primary_cursor),
|
||||||
|
secondary_cursor: Some(secondary_cursor),
|
||||||
|
text_value: Some(text_value.to_string()),
|
||||||
|
..Self::new(WidgetType::TextEdit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This can be used by a text-to-speech system to describe the widget.
|
/// This can be used by a text-to-speech system to describe the widget.
|
||||||
pub fn description(&self) -> String {
|
pub fn description(&self) -> String {
|
||||||
let Self {
|
let Self {
|
||||||
|
@ -345,6 +377,8 @@ impl WidgetInfo {
|
||||||
prev_text_value: _,
|
prev_text_value: _,
|
||||||
selected,
|
selected,
|
||||||
value,
|
value,
|
||||||
|
primary_cursor: _,
|
||||||
|
secondary_cursor: _,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
// TODO: localization
|
// TODO: localization
|
||||||
|
|
|
@ -65,6 +65,8 @@ pub struct Response {
|
||||||
/// e.g. the slider was dragged, text was entered in a `TextEdit` etc.
|
/// e.g. the slider was dragged, text was entered in a `TextEdit` etc.
|
||||||
/// Always `false` for something like a `Button`.
|
/// Always `false` for something like a `Button`.
|
||||||
pub(crate) changed: bool,
|
pub(crate) changed: bool,
|
||||||
|
/// Has a `WidgetInfo` but isn't covered by some other case (E.g. `changed`, `clicked`.)
|
||||||
|
pub(crate) has_widget_info: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for Response {
|
impl std::fmt::Debug for Response {
|
||||||
|
@ -84,6 +86,7 @@ impl std::fmt::Debug for Response {
|
||||||
is_pointer_button_down_on,
|
is_pointer_button_down_on,
|
||||||
interact_pointer_pos,
|
interact_pointer_pos,
|
||||||
changed,
|
changed,
|
||||||
|
has_widget_info,
|
||||||
} = self;
|
} = self;
|
||||||
f.debug_struct("Response")
|
f.debug_struct("Response")
|
||||||
.field("layer_id", layer_id)
|
.field("layer_id", layer_id)
|
||||||
|
@ -99,6 +102,7 @@ impl std::fmt::Debug for Response {
|
||||||
.field("is_pointer_button_down_on", is_pointer_button_down_on)
|
.field("is_pointer_button_down_on", is_pointer_button_down_on)
|
||||||
.field("interact_pointer_pos", interact_pointer_pos)
|
.field("interact_pointer_pos", interact_pointer_pos)
|
||||||
.field("changed", changed)
|
.field("changed", changed)
|
||||||
|
.field("has_widget_info", has_widget_info)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -437,6 +441,13 @@ impl Response {
|
||||||
Some(OutputEvent::FocusGained(make_info()))
|
Some(OutputEvent::FocusGained(make_info()))
|
||||||
} else if self.changed {
|
} else if self.changed {
|
||||||
Some(OutputEvent::ValueChanged(make_info()))
|
Some(OutputEvent::ValueChanged(make_info()))
|
||||||
|
} else if self.has_widget_info {
|
||||||
|
let info = make_info();
|
||||||
|
if info.primary_cursor.is_some() && info.secondary_cursor.is_some() {
|
||||||
|
Some(OutputEvent::TextSelectionChanged(info))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -479,6 +490,7 @@ impl Response {
|
||||||
|| other.is_pointer_button_down_on,
|
|| other.is_pointer_button_down_on,
|
||||||
interact_pointer_pos: self.interact_pointer_pos.or(other.interact_pointer_pos),
|
interact_pointer_pos: self.interact_pointer_pos.or(other.interact_pointer_pos),
|
||||||
changed: self.changed || other.changed,
|
changed: self.changed || other.changed,
|
||||||
|
has_widget_info: self.has_widget_info || other.has_widget_info,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -665,7 +665,18 @@ impl<'t> TextEdit<'t> {
|
||||||
|
|
||||||
ui.memory().id_data.insert(id, state);
|
ui.memory().id_data.insert(id, state);
|
||||||
|
|
||||||
|
if response.changed {
|
||||||
response.widget_info(|| WidgetInfo::text_edit(&*text, &*prev_text));
|
response.widget_info(|| WidgetInfo::text_edit(&*text, &*prev_text));
|
||||||
|
} else if let Some(text_cursor) = text_cursor {
|
||||||
|
response.has_widget_info = true;
|
||||||
|
response.widget_info(|| {
|
||||||
|
WidgetInfo::text_selection_changed(
|
||||||
|
text_cursor.primary.ccursor.index,
|
||||||
|
text_cursor.secondary.ccursor.index,
|
||||||
|
&*text,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue