mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-13 20:08:42 +00:00
UI: a tap within 1 pt still selects a numeric field's value (#1326)
Review feedback: with no tolerance, pen or trackpad jitter turned a tap into a drag and the value was no longer selected. A release within 1 pt of the press is a tap; anything further keeps the caret. Regression test: a_tap_with_a_pixel_of_jitter_still_selects_all_on_release.
This commit is contained in:
@@ -1361,8 +1361,8 @@ fn a_short_drag_released_as_a_click_keeps_its_caret() {
|
||||
assert_eq!(f.frame(vec![enter()], &draw), Some(1273456.0), "typing lands where the drag left the caret");
|
||||
}
|
||||
|
||||
/// #1326: the smallest pointer movement egui still reports as a click (under the 3-point drag
|
||||
/// threshold) must keep the caret too; only a press released where it went down selects all.
|
||||
/// #1326: a pointer movement well under egui's click tolerance must keep the caret too; only a
|
||||
/// press released within a point of where it went down selects all.
|
||||
#[test]
|
||||
fn a_sub_threshold_movement_released_as_a_click_keeps_its_caret() {
|
||||
let mut f = Field::new();
|
||||
@@ -1391,6 +1391,20 @@ fn a_tap_without_movement_still_selects_all_on_release() {
|
||||
assert_eq!(f.selection(), Some((0, field_text(0).chars().count())), "a plain tap selects all");
|
||||
}
|
||||
|
||||
/// A pen or trackpad tap often moves a pixel between press and release: it is still a tap.
|
||||
#[test]
|
||||
fn a_tap_with_a_pixel_of_jitter_still_selects_all_on_release() {
|
||||
let mut f = Field::new();
|
||||
let draw = |ui: &mut egui::Ui| numeric_fixture(ui, 0);
|
||||
f.frame(vec![], &draw);
|
||||
let at = f.text_point(field_text(0), 2, 7.0);
|
||||
f.frame(vec![Event::PointerMoved(at), pointer_button(at, true)], &draw);
|
||||
let jitter = egui::vec2(0.7, -0.6);
|
||||
f.frame(vec![Event::PointerMoved(at + jitter)], &draw);
|
||||
f.frame(vec![pointer_button(at + jitter, false)], &draw);
|
||||
assert_eq!(f.selection(), Some((0, field_text(0).chars().count())), "a jittery tap selects all");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keyboard_focus_keeps_selecting_the_entire_numeric_field() {
|
||||
for mode in 0..4 {
|
||||
|
||||
@@ -147,10 +147,14 @@ pub(crate) fn own_field_shift_enter(ui: &Ui, id: egui::Id, buf: &mut String, sho
|
||||
shift_enter_keeps_focus(ui, id)
|
||||
}
|
||||
|
||||
/// How far, in points, a focus click may move between press and release and still be a tap that
|
||||
/// selects the whole numeric value. Covers pen and trackpad jitter; anything further is a drag.
|
||||
const TAP_SLOP: f32 = 1.0;
|
||||
|
||||
/// Numeric fields select the whole text on keyboard focus, a completed focus click or a
|
||||
/// double-click. A pointer press keeps its caret so dragging selects from the pressed position,
|
||||
/// and a short drag the toolkit still counts as a click keeps it too (#1326): only a tap
|
||||
/// releases into select-all.
|
||||
/// (released within [`TAP_SLOP`] of its press) releases into select-all.
|
||||
pub(super) fn select_all_on_focus(ui: &Ui, resp: &Response, text: &str) {
|
||||
let pending = resp.id.with("select-all-on-focus-click");
|
||||
let press_pos = resp.id.with("select-all-on-focus-press");
|
||||
@@ -171,13 +175,14 @@ pub(super) fn select_all_on_focus(ui: &Ui, resp: &Response, text: &str) {
|
||||
});
|
||||
}
|
||||
let clicked_focus = released && ui.data_mut(|d| d.remove_temp::<bool>(pending)).unwrap_or(false) && resp.clicked_by(egui::PointerButton::Primary);
|
||||
// Any pointer movement from the press is a drag, not a tap. egui still reports a click for
|
||||
// a movement under its click tolerance, and a release inside one character leaves no text
|
||||
// selection, so select-all on release would replace the drag the user just made (#1326).
|
||||
// A pointer released more than a point from its press is a drag, not a tap. egui still
|
||||
// reports a click for a movement under its click tolerance, and a release inside one
|
||||
// character leaves no text selection, so select-all on release would replace the drag the
|
||||
// user just made (#1326). The one point of slack keeps a jittery pen or trackpad tap a tap.
|
||||
let dragged = clicked_focus
|
||||
&& ui
|
||||
.data_mut(|d| d.remove_temp::<egui::Pos2>(press_pos))
|
||||
.is_some_and(|p0| ui.input(|i| i.pointer.interact_pos()).is_some_and(|p1| (p1 - p0).length() > 0.0));
|
||||
.is_some_and(|p0| ui.input(|i| i.pointer.interact_pos()).is_some_and(|p1| (p1 - p0).length() > TAP_SLOP));
|
||||
if resp.lost_focus() {
|
||||
ui.data_mut(|d| {
|
||||
d.remove_temp::<bool>(pending);
|
||||
|
||||
+1
-1
@@ -320,7 +320,7 @@ macOS cursor delivery (#2292) is narrowed to a native host adapter using the exi
|
||||
|
||||
- **Done:** Divide splits filled paths along open cutting lines and curves (#1307), preserving the frontmost filled appearance, implicit filled closure, holes, unrelated objects and one Undo/Redo; the existing bounded-map fallback remains.
|
||||
|
||||
- **Done:** Numeric fields keep a text drag's start when the pointer gains focus, including short movements that egui still classifies as clicks (#1326). Any pointer movement from the press keeps the caret; only a tap without movement selects the whole value. Keyboard focus, double-click and numeric stepping remain regression-tested (`tests/numfields.rs`, `a_short_drag_released_as_a_click_keeps_its_caret` and `a_sub_threshold_movement_released_as_a_click_keeps_its_caret`).
|
||||
- **Done:** Numeric fields keep a text drag's start when the pointer gains focus, including short movements that egui still classifies as clicks (#1326). A release more than 1 pt from the press keeps the caret; a tap, including one with a pixel of pen or trackpad jitter, selects the whole value. Keyboard focus, double-click and numeric stepping remain regression-tested (`tests/numfields.rs`, `a_short_drag_released_as_a_click_keeps_its_caret` and `a_sub_threshold_movement_released_as_a_click_keeps_its_caret`).
|
||||
|
||||
- **Done:** DXF reads control-point SPLINE closure (#1299 follow-up after #1320); open curves keep their open state. DXF export now recognizes circular cubic paths conservatively and writes native CIRCLE/ARC where stroke semantics permit; R12 weighted strokes remain POLYLINE, and a non-circular ellipse keeps the existing fallback. Alter Paths for Appearance outlines only the strokes a CAD line can't draw (aligned, profiled, offset dashes, wider than 2.11 mm, or in R13 and R14), so a 1 pt circle or arc stays a CIRCLE or ARC. CNC preset and VCarve QA remain open. Escape leaves Artboard editing for Selection; during a drag it first cancels the gesture. Headless egui key events cover idle Escape, active-drag cancellation and a subsequent Escape in `tests/distortkeys.rs`.
|
||||
- **Done:** DXF reads control-point SPLINE closure (#1299 follow-up after #1320); open curves keep their open state. DXF export now recognizes circular cubic paths conservatively and writes native CIRCLE/ARC where stroke semantics permit; R12 weighted strokes remain POLYLINE. A closed four-cubic ellipse, or a circle scaled out of proportion, is written as a native ELLIPSE in R13 and later; R12 keeps the existing fallback. CNC preset and VCarve QA remain open. Escape leaves Artboard editing for Selection; during a drag it first cancels the gesture. Headless egui key events cover idle Escape, active-drag cancellation and a subsequent Escape in `tests/distortkeys.rs`.
|
||||
|
||||
Reference in New Issue
Block a user