diff --git a/crates/oa-desktop/src/app.rs b/crates/oa-desktop/src/app.rs index 3bd5f097..72b98492 100644 --- a/crates/oa-desktop/src/app.rs +++ b/crates/oa-desktop/src/app.rs @@ -216,11 +216,14 @@ mod direct_scenario_tests { let _ = app.update(Message::ScenarioCanvas(CanvasEvent::Select( context, f.sender, ))); - assert_eq!( - app.scenario_context(), - Some(context), - "same-owner selection retains gesture context" + let fresh = app.scenario_context().unwrap(); + assert_eq!(fresh.visit, context.visit); + assert_eq!(fresh.representation, context.representation); + assert_ne!( + fresh.epoch, context.epoch, + "selection retires older gestures" ); + let context = fresh; let _ = app.update(Message::ScenarioCanvas(CanvasEvent::Reorder { context, occurrence: created, @@ -1379,6 +1382,10 @@ impl App { } let preview_read_only = self.process_preview_primary().is_some(); let selection_boundary = self.multiselect_boundary(); + let scenario_selection_before = self.scenario_context().and_then(|context| { + self.multiselect_snapshot() + .map(|selection| (context, selection)) + }); // Reject delayed gestures before they can retire newer input ownership. if let Message::Connection( crate::connection_edit::Event::Endpoint(captured, _) @@ -1644,6 +1651,16 @@ impl App { { self.reconcile_multiselect(); } + if let Some((context, selection)) = scenario_selection_before + && self.scenario_context() == Some(context) + && self.multiselect_snapshot().as_ref() != Some(&selection) + { + // Legacy singleton selection retires old spacing packets. If the + // action already advanced its context, its new navigation/reveal + // owns that context and must not be retired by reconciliation. + self.behavior.scenario.cancel_spacing(); + self.canvas_epoch = self.canvas_epoch.wrapping_add(1); + } if preview_read_only && self.process_preview_primary().is_none() && self.draft.is_none() { self.refresh_draft(); } diff --git a/crates/oa-desktop/src/app/scenario_multiselect.rs b/crates/oa-desktop/src/app/scenario_multiselect.rs index 7f3d1491..fd5e4828 100644 --- a/crates/oa-desktop/src/app/scenario_multiselect.rs +++ b/crates/oa-desktop/src/app/scenario_multiselect.rs @@ -20,7 +20,6 @@ impl App { return; }; let scope = selection::context(context).scope; - let before = self.multiselect_snapshot(); let visible = selection::visible(self.project(), context, self.selected); let old = self .diagram_selection @@ -46,13 +45,6 @@ impl App { selected.clear(); } } - if before.is_some() && self.multiselect_snapshot() != before { - // Legacy singleton selection also retires captured spacing input. - // This must not change the camera lifetime: blank selection input - // and a new background pan can share the same pointer press. - self.behavior.scenario.cancel_spacing(); - self.canvas_epoch = self.canvas_epoch.wrapping_add(1); - } } pub(super) fn inspect_scenario_multiselect_primary(&mut self) {