Merge PR #1993: Grid: the selection outline follows a mouse drag at once

Conflicts:
- docs/ui-parity.md: header keeps main's change list plus the outline entry; both log rows kept
This commit is contained in:
aiongg
2026-10-22 02:37:23 +00:00
3 changed files with 32 additions and 2 deletions
+4 -1
View File
@@ -722,6 +722,9 @@ pub fn show(app: &mut SheetApp, ui: &mut egui::Ui) {
app.grid.cells_rect = Some(geo.mirror_rect(geo.cells));
// The selection outline glides to a new selection. It stays on its cells when Animations is
// off, when egui's animations are (the headless harness), and while a screenshot is on its way.
// A mouse button held down (a click or a drag selecting cells) moves it at once, as in Excel:
// a gliding outline trails the pointer and reads as lag.
let pointer_selecting = ui.input(|i| i.pointer.any_down());
let outline = app.grid.glide.frame(crate::selection_glide::Frame {
place,
range: sel.current(),
@@ -729,7 +732,7 @@ pub fn show(app: &mut SheetApp, ui: &mut egui::Ui) {
view: geo.cells,
now,
frame_nr: ui.ctx().cumulative_frame_nr(),
animate: app.ui.animations && ui.ctx().global_style().animation_time > 0.0 && !app.shots.in_flight(),
animate: app.ui.animations && ui.ctx().global_style().animation_time > 0.0 && !app.shots.in_flight() && !pointer_selecting,
});
if app.grid.glide.is_gliding() {
ui.ctx().request_repaint();
+26
View File
@@ -201,3 +201,29 @@ fn agents_find_run_and_read_the_setting_over_the_control_channel() {
assert_eq!(set["result"]["animations"], json!(true));
assert!(a.ui.animations);
}
#[test]
fn a_mouse_drag_keeps_the_outline_on_its_cells() {
// A gliding outline trails the pointer while selecting with the mouse and reads as lag; Excel
// draws it on the selection at once. Keyboard moves still glide (above).
let mut h = animated();
let (b2, e8) = (cell_rect(&h, "B2"), cell_rect(&h, "E8"));
let m = egui::Modifiers::NONE;
h.input_mut().events.extend([
egui::Event::PointerMoved(b2.center()),
egui::Event::PointerButton { pos: b2.center(), button: egui::PointerButton::Primary, pressed: true, modifiers: m },
]);
h.step();
for k in 1..=6 {
let p = b2.center() + (e8.center() - b2.center()) * (k as f32 / 6.0);
h.input_mut().events.push(egui::Event::PointerMoved(p));
steps(&mut h, 2);
let sel = h.state().session.active().map(|d| d.selection.current()).unwrap();
let shown = cell_rect(&h, &sel.start.a1()).union(cell_rect(&h, &sel.end.a1()));
assert!(!gliding(&h), "no glide while the button is held");
assert_eq!(outline(&h), shown, "the outline is on the dragged range {}", sel.a1());
}
h.input_mut().events.push(egui::Event::PointerButton { pos: e8.center(), button: egui::PointerButton::Primary, pressed: false, modifiers: m });
h.step();
assert_eq!(h.state().session.active().map(|d| d.selection.current().a1()).as_deref(), Some("B2:E8"));
}