LR-BEHAV-TEXTFIELD: a drag into a select-on-focus field keeps its selection

Select-on-focus selected everything on the press that took the focus,
after egui had placed the drag's anchor there: a drag then selected
from the start of the text. With a press, the field now waits for the
release and selects everything only after a plain click, as a
browser's address bar does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Nathaniel Ledford
2026-10-09 13:23:10 -04:00
co-authored by Claude Opus 5.5
parent 6fb1a24c88
commit a6e59cc5b3
+35
View File
@@ -195,9 +195,22 @@ impl<'a> TextField<'a> {
memo.before = None;
}
// the start of an edit (not the focus coming back from the menu)
let pressing = ui.input(|i| i.pointer.any_down());
if focused && memo.before.is_none() {
memo.before = Some(self.text.clone());
if self.select_on_focus {
// a press that took the focus may go on to drag a selection: wait for its release
if pressing {
memo.select_on_release = true;
} else {
select_all(ui.ctx(), id, self.text);
}
}
}
if memo.select_on_release && !pressing {
memo.select_on_release = false;
// a plain click selects everything; a drag keeps what it selected
if focused && !has_selection(ui.ctx(), id) {
select_all(ui.ctx(), id, self.text);
}
}
@@ -264,6 +277,9 @@ struct Memo {
action: Option<Action>,
/// The focus left for the menu: the edit ends if the menu closes without a choice.
away: bool,
/// The field took the focus with select-on-focus under a press: select all on its release,
/// unless it dragged a selection.
select_on_release: bool,
/// The frame (egui pass) the field was last drawn in.
pass: u64,
}
@@ -666,4 +682,23 @@ mod tests {
rig.key(Key::Escape, Modifiers::NONE);
assert_eq!(rig.text, "Porto");
}
/// A field that selects on focus still lets a drag into it select part of the text, as a
/// browser's address bar does: only a plain click selects everything.
#[test]
fn a_drag_into_a_field_that_selects_on_focus_selects_what_it_covers() {
let mut rig = Rig::new("Lisbon Portugal Europe Atlantic Ocean");
rig.select_on_focus = true;
let r = rig.rect(FIELD).expect("the field");
let (from, to) = (r.center(), egui::pos2(r.right() + 40.0, r.center().y));
let press = |at, pressed| Event::PointerButton { pos: at, button: PointerButton::Primary, pressed, modifiers: Modifiers::NONE };
rig.frame(vec![Event::PointerMoved(from), press(from, true)]);
for i in 1..=5 {
rig.frame(vec![Event::PointerMoved(from + (to - from) * (i as f32 / 5.0))]);
}
rig.frame(vec![press(to, false)]);
rig.settle();
rig.type_text("X");
assert!(rig.text.starts_with("Lisbon") && rig.text.ends_with('X') && rig.text != "X", "{:?}", rig.text);
}
}