From 6785be8a3e1e67f775009e47f7f383775be8eb30 Mon Sep 17 00:00:00 2001 From: Trevor Brown Date: Thu, 12 Nov 2026 13:43:50 -0500 Subject: [PATCH] M8: an icon double-click becomes the range anchor A Shift-double-click on a layer's icon leaves only that layer selected, but the range anchor stayed on the layer clicked before, which was no longer selected, so the next Shift-click toggled instead of selecting a range. The icon branch now makes its layer the anchor. Co-Authored-By: Claude Sonnet 5.5 Model-Effort: Opus 5.5 drove; Fable 5.2 queued; Sonnet 5.5 measured and wrote at medium --- crates/ui-egui/src/layers_behaviour_tests.rs | 24 ++++++++++++++++++++ crates/ui-egui/src/panels/layers.rs | 2 ++ 2 files changed, 26 insertions(+) diff --git a/crates/ui-egui/src/layers_behaviour_tests.rs b/crates/ui-egui/src/layers_behaviour_tests.rs index 0a825bdbb..93a80d9bd 100644 --- a/crates/ui-egui/src/layers_behaviour_tests.rs +++ b/crates/ui-egui/src/layers_behaviour_tests.rs @@ -914,3 +914,27 @@ fn an_icon_double_click_keeps_its_selection_when_a_modifier_is_held() { let v = &u.app.session.ds().unwrap().view; assert_ne!((v.cx, v.zoom), before, "the view frames the layer"); } + +/// A Shift-double-click on an icon leaves just that layer selected, and it becomes the anchor: the +/// next Shift-click selects the range from it, not a toggle. +#[test] +fn an_icon_double_click_becomes_the_range_anchor() { + let (mut u, [a, b, c, d]) = four(); + u.frame(vec![]); + let a_row = u.row_at(a); + click(&mut u, a_row, Modifiers::NONE); + let icon = icon_of(&mut u, b); + for _ in 0..2 { + for pressed in [true, false] { + let e = Event::PointerButton { pos: icon, button: egui::PointerButton::Primary, pressed, modifiers: SHIFT }; + u.frame_with(vec![Event::PointerMoved(icon), e], SHIFT); + } + } + for _ in 0..30 { + u.frame(vec![]); + } + assert_eq!(u.app.session.selection(), vec![b], "the icon's layer is all that is selected"); + let d_row = u.row_at(d); + click(&mut u, d_row, SHIFT); + assert_eq!(sorted(u.app.session.selection()), sorted(vec![b, c, d]), "the range from the icon's layer"); +} diff --git a/crates/ui-egui/src/panels/layers.rs b/crates/ui-egui/src/panels/layers.rs index da7454141..d4deb034d 100644 --- a/crates/ui-egui/src/panels/layers.rs +++ b/crates/ui-egui/src/panels/layers.rs @@ -1271,6 +1271,8 @@ fn layers(app: &mut FigApp, ui: &mut Ui) { app.run("view.zoomSelection", json!({})); // The release is also a click: it must not toggle or extend the selection. clicked = None; + // The layer is the anchor of the next Shift-click's range. + app.ui.layer_anchor = Some(row.id); } else if !crate::menus::dev_mode_refuses(app, "object.rename") { app.ui.rename = Some(Rename { id: row.id, start: true }); }