Files
ARCADIA-Studio/harness/picker-escape-20260923.md
T

4.4 KiB

Picker Escape ownership — issue 35

Branch-specific design above 301126f6098286bf440c1bd1b1ed685753984723. Issue 35 owns live scope, progress and acceptance. This document records the selected contract; it does not assert completed implementation, execution or integration.

Required interaction

An open picker owns Escape: close its popup, request redraw and consume the key. Publish its optional close notification at most once; do not select an option or change the surrounding draft, model, source, history, selection or camera. A later Escape follows the existing surrounding workflow's policy. Reopening, selection and outside-click dismissal retain their existing behavior. Selection does not gain a new close callback as an incidental change to this repair.

Event batches matter. A popup already closed by Escape must not select a stale option or emit another close notification when later queued events reach the same overlay object. This does not introduce a new global keyboard-repeat policy.

Decision and evidence

The shared picker and its menu overlay currently omit Escape handling. Adding widget capture alone is insufficient: application subscriptions translate some captured Escape events back into modal cancellation. Those bridges also preserve legitimate cancellation from focused text inputs, so simply removing them loses existing behavior.

The selected design gives dismissal to the picker overlay and moves the existing captured-key forwarding into a scoped wrapper around the ordinary application widget tree. Keep the wrapper structurally present even when inactive, preserve the existing activation predicates and message priorities, and delegate widget state, operations, layout and overlays transparently.

The locked Iced 0.14 runtime processes overlays first and skips ordinary root updates for events captured by an overlay (user_interface.rs). Nested overlays likewise give their deepest child first refusal (overlay/nested.rs). Thus the Escape from an already mounted picker cannot reach ordinary-tree forwarding, while focused text-input cancellation can retain its previous policy. The runtime can reuse an overlay across an event batch; close-state checks must cover that case. Conversely, opening a picker and pressing Escape in the same batch can reach the ordinary tree before the runtime constructs its overlay. The wrapper therefore offers the currently available nested overlay first refusal for Escape before forwarding to ordinary children; the picker also handles base delivery. An overlay that already ignored Escape may receive this narrow preflight again. Audited reachable passive overlays perform no selection or draft action; the source-navigation observer can advance its conservative focus-freshness epoch again. Regression checks must retain stale-focus rejection and observable state. Do not generalize this replay to other keyboard or pointer events.

Alternatives rejected: a widget-only patch leaves outer-draft cancellation; global open-picker bookkeeping duplicates widget state and requires coordinating every open/select/close/removal path; per-text-input forwarding can work but spreads the existing policy across many controls. Revisit the wrapper choice if runtime delivery changes or actual mounted tests contradict these assumptions.

Acceptance

Use mounted runtime delivery for open/dismiss/reopen/select, optional callbacks, outside click and same-batch Escape/click sequences. Exercise the real application subscriptions with returned event status, including focused text cancellation, architecture editing, behavior drafts and Text workflows. Compare complete model and source state where dismissal must conserve them; direct helper calls alone do not establish event ownership.

Native coverage should include the State hidden-element picker and the Add existing chooser's filter dropdown with a retained query: first Escape dismisses the picker, then a distinct Escape follows the chooser policy. Behavior creation, behavior source forms and Text Find/rename currently have no internal dropdown; picker coexistence there is composed mounted coverage, not a claim of a native control that does not exist. Verify their ordinary focused-text Escape behavior.

Linux remains user-paused. Shared integration and release acceptance remain with the integration owner; this branch does not establish combined-release behavior.