From a9cd364eacbbffa0693bab05b5a2b65f9d105535 Mon Sep 17 00:00:00 2001 From: Codex-ytr83r Date: Thu, 24 Sep 2026 00:25:25 -0700 Subject: [PATCH] Locate State picker from measured bounds in mounted Escape regression --- .../src/app/state_picker_escape_tests.rs | 21 +++++++++---------- crates/oa-desktop/src/behavior/state_view.rs | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/crates/oa-desktop/src/app/state_picker_escape_tests.rs b/crates/oa-desktop/src/app/state_picker_escape_tests.rs index 63cbfcaf..09ccf92c 100644 --- a/crates/oa-desktop/src/app/state_picker_escape_tests.rs +++ b/crates/oa-desktop/src/app/state_picker_escape_tests.rs @@ -10,6 +10,11 @@ async fn press_escape(mounted: &mut Mounted, app: &mut App) -> Vec { std::slice::from_ref(&input), mouse::Cursor::Unavailable, ); + assert_eq!( + statuses, + [iced::event::Status::Captured], + "the mounted picker must capture Escape before App subscriptions" + ); crate::app::escape::tests::subscriptions(app, input, statuses[0], &mut messages); for message in messages.iter().cloned() { let task = app.update(message); @@ -41,17 +46,11 @@ async fn mounted_state_missing_picker_escape_preserves_exact_document_then_reope send(&mut app, Message::BehaviorDiagram(choice)); let mut mounted = Mounted::new(&mut app).await; assert_eq!(state_edit::unplaced(app.project(), diagram), vec![f.b]); - let focus_id = iced::advanced::widget::Id::from("diagram-keyboard-owner"); - let (_, canvas, _) = mounted - .geometry(&app) - .focused - .into_iter() - .find(|(id, _, _)| id.as_ref() == Some(&focus_id)) - .unwrap(); - // The existing picker is immediately above the measured canvas, separated - // by 8px. Its 12px text and 8px padding give a 31.6px row. - let picker = iced::Point::new(canvas.center_x(), canvas.y - 24.); - let option = iced::Point::new(picker.x, canvas.y + 8.); + // Locate the stable picker slot itself: selection controls may sit between + // it and the canvas. The single menu option opens below this slot. + let bounds = mounted.geometry(&app).bounds("state-missing-picker"); + let picker = bounds.center(); + let option = iced::Point::new(picker.x, bounds.y + bounds.height * 1.5); let before = app.document.snapshot(); let original = app.project().clone(); let source = app.document.bundle().clone(); diff --git a/crates/oa-desktop/src/behavior/state_view.rs b/crates/oa-desktop/src/behavior/state_view.rs index e7d5785f..03f86215 100644 --- a/crates/oa-desktop/src/behavior/state_view.rs +++ b/crates/oa-desktop/src/behavior/state_view.rs @@ -187,7 +187,7 @@ pub fn view<'a>(app: &'a App, machine: Id, mut out: Column<'a, Message>) -> Elem .into(); out = out.push( column![ - missing_controls, + container(missing_controls).id("state-missing-picker"), selection_controls(app), crate::diagram::focus::wrap( canvas.map(event),