Skip to content

Use the panel UI for Home and action menus - #1042

Merged
enaboapps merged 6 commits into
mainfrom
claude/1041-menu-panels
Oct 13, 2026
Merged

enaboapps merged 6 commits into
mainfrom
claude/1041-menu-panels

Conversation

@enaboapps

@enaboapps enaboapps commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Closes #1041

What changed

Layout. Every menu kind (Home, Actions, Scroll, Confirm drag, More, Mouse actions and all their submenus) is now drawn as a scan_panel::Panel, built by a new Menu::frame(screen, units, dock, error) in scan_menu.rs.

  • Each item is a text key, using its existing label, with weight 1.
  • key_width is 176, so a three-column menu is about as wide as the mouse panel.
  • Back, Close menu, Cancel drag and Home use the toolbar role. Everything else uses the utility role.
  • Rows, items, navigation, commands and Policy::MENU scan timing are unchanged.

Header. The panel status tile replaces the floating menu title. Its wording follows the panels:

  • Home · Select a row and Actions · Select Left click
  • Back to rows · Select to return
  • <Menu> paused · Select to resume
  • <Menu> · Select to continue

Kind::Actions is now titled "Actions" instead of "Choose an action", so it reads as a page name like the panels' pages.

Position.

  • Menus use the shared Workflow.dock. With Remember the scanning panel position between sessions #1040 merged, that includes the saved panel position.
  • They go through the same avoiding() and move_frame path as the keyboard and mouse panels, so they follow "Move away from the pointer".
  • Menus have no Position page. The position is still chosen on the keyboard or mouse panel, and menus never change it, so the unsaved_dock/dock_saved flow from Remember the scanning panel position between sessions #1040 applies unchanged. A test now covers Home opening at the restored dock without marking it unsaved.
  • point_scan_runtime now passes the pointer to the workflow while Home or a point menu is open and pointer avoidance is on. Before, only the keyboard and mouse panels received it.

Points. The crosshair still marks the chosen point on point menus. Confirm drag also marks the destination, because the docked menu no longer sits beside it.

Errors. The menu's status stays one short line, for example Actions · Action failed · Select to return, and nothing is highlighted until Select.

  • The full message (<error> Select to return) is shown in the HUD prompt that the countdown and drag-destination prompts also use, so no new rendering code was added.
  • The prompt is placed in the menu's work area, so it does not sit over the taskbar or menu bar.
  • It goes in the larger gap above or below the panel. If neither gap fits it, it goes in the wider gap beside the panel, at a narrower width of at least 240 units.
  • It only overlaps the panel when no gap fits at all.
  • A blank message reads "Action failed.".
  • The height kept clear is 154 units, because the Windows prompt is always drawn that tall. The shared prompt rendering was not changed, so on Windows the text still sits at the top of that box.
  • Long errors such as "Release modifiers and end switch forwarding before selecting an action." are therefore not clipped.

Removed code that became dead.

  • The square artwork in scan_tile.rs: all of the icon drawing and its helpers, about 750 lines.
  • FrameTile.icon, Item::KeyboardKey, Menu::centered_frame and place().
  • The artwork branch of Windows present_scan_tile.
  • The artwork label branch of macOS Host::tile.
  • MenuTitle, menu_title_geometry and macOS Host::menu_title. Host::label and render_label no longer take tiles.

Settings copy (ScannerPreferences.tsx).

  • The "Panel position" group now also shows on the Menus page. It says the keyboard, mouse panel, Home and action menus share one position.
  • The pointer note says "a panel or menu".
  • The Panel size note and the Menus description now mention menus.
  • No persisted or synced schema changed.

Judgement calls and what was left alone

  • Scan policy: menus keep Policy::MENU and their own colour, thickness, timing and size overrides. The panel policy was not needed.
  • Area: menus dock in a work area on the display they act on (point.screen).
    • A menu opened from the mouse panel prefers mouse_area. Any other menu prefers keyboard_area.
    • Each area is kept current only while its own panel is in use, so menu_area() skips any area that is not inside point.screen and falls back to point.screen itself.
  • Covering the point: as decided for this issue, a docked menu may cover the chosen point. The crosshair still marks it, and pointer avoidance moves the menu when the real pointer is under it. The independent review raised this as a possible usability concern. It is left as designed and needs checking on real devices, including whether the crosshair strips draw above the opaque panel.
  • FrameTile.style: it stays an Option, even though every tile now has a style, to keep the diff focused.
  • Help demonstrations: the SVG demonstrations under src/help are separate artwork and were not changed.
  • Not fixed here: after the mouse panel moves to another display, the runtime does not seem to update the workflow's keyboard_area when the keyboard then opens. This change does not touch that. Menus avoid it through the containment check.

Validation (Windows 11, Node 24.13.0)

  • npm run lint: passed
  • npm test: 13 files and 295 tests passed, plus 12 of 12 node tests
  • npm run build: passed
  • cargo fmt --check: clean
  • cargo clippy --all-targets -- -D warnings: clean (Windows target)
  • cargo test at 1dc0f0a: 761 passed, 0 failed, 5 ignored, plus 7 integration tests passed
    • On one run, the unrelated, timing-sensitive prediction::tests::cancellation_kills_and_reaps_a_blocked_worker failed after a 53 s run. The rerun passed in full.
  • npm checks were not rerun after the error fix, because it touched no TypeScript.
  • npm run prediction-model was not run, because of a local EPERM rename lock on this machine. The gitignored src-tauri/resources/prediction-model, src-tauri/resources/prediction-neural and src-tauri/binaries were copied from the main checkout.
  • The macOS-only code in scan_host.rs could not be compiled here. An independent reviewer read it and found no compile issues. macOS CI should confirm.
  • New and rewritten tests:
    • Every menu kind at every panel size, three screen sizes, three scales and all nine docks fits the screen, is anchored at its dock and shows every item as a text key.
    • Row and item highlighting and the status wording.
    • Errors and pauses show no highlight.
    • The rounded panel insets its keys below the header.
    • Workflow: menus share the dock, avoid the pointer, keep the crosshair, mark both ends of a drag and skip a stale work area.
    • Home opens at the saved dock.
    • For the two longest known errors at Small panel size, with the panel at the top and at the bottom, the status is the short fixed text and the full message is in frame.label.
    • Placement of the error prompt is checked across five displays (1280x720 logical at 100%, 150% and 200%, one display placed at negative coordinates, 1366x768 and 1920x1080) with a taskbar work area. Every case covers all nine docks and every panel size, with and without pointer avoidance moving the panel. The prompt stays inside the work area and never overlaps the panel, and the test asserts that the panel moved.
    • An empty error message falls back to "Action failed.".
  • An independent review agent checked the head before this PR was opened.
  • A second independent review at 2e924e1 found that long error messages were clipped in the status tile. This is fixed in cf39e84.
  • A review of cf39e84 found that the prompt could cover the panel or the taskbar, could leave the screen on short displays, and showed a blank first line for empty messages. This is fixed in 21bc931.
  • A review of 21bc931 found that the prompt could still overlap Large panels docked at the left, middle or right. This is fixed in 1dc0f0a by placing it beside the panel when it fits neither above nor below.
  • Not changed: the error prompt text is not centred vertically in the Windows prompt box, because that is shared prompt rendering.
  • Existing behaviour, not changed here: after Select clears an error, the menu shows paused · Select to resume, so a second Select is needed.

Needs a real-device check

Check Windows and macOS (npm run macos:run):

  • Home and each submenu at Small, Medium and Large sizes, on both a single display and multiple displays.

  • Pointer avoidance on Home and point menus.

  • That the crosshair is visible when a menu covers the point.

  • An error message in a menu.

  • That long labels wrap within keys on both platforms.

  • Independent review of the latest head 1dc0f0a reported no actionable findings. It checked placement of the error prompt above, below or beside the panel on Windows and macOS, confirmed with a deliberately broken version that the placement test catches regressions, and read the macOS code for compile problems.

🤖 Generated with Claude Code

OwenMcGirr and others added 3 commits October 13, 2026 13:16
Every menu kind renders as a scan_panel::Panel with text keys and the
panel status header, docked at the shared panel position and moved out
of the pointer's way like the keyboard and mouse panels. Point menus
keep the crosshair, and Confirm drag also marks the destination. Errors
show in the menu's status. The square menu artwork, the tile icon field
and the menu title host are removed on Windows and macOS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@enaboapps enaboapps added this to the v1.0.0-rc.25 milestone Oct 13, 2026
OwenMcGirr and others added 3 commits October 13, 2026 13:39
Long failure messages wrapped past the one-line status tile and lost
"Select to return". The status now reads "<Menu> · Action failed ·
Select to return", and the full message is shown in the shared HUD
prompt at the end of the screen the menu panel leaves clear.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The prompt now goes in the larger space the docked panel leaves in the
menu's work area, kept inside that area, so it no longer covers tall or
middle panels, the taskbar or the menu bar. An empty message reads
"Action failed.".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When neither gap above nor below the docked menu fits the prompt, it
goes in the wider gap beside the panel at a narrower width. The test
covers all nine docks, every panel size and 1280x720 displays at 100,
150 and 200 percent, and checks that pointer avoidance moved the panel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@enaboapps
enaboapps marked this pull request as ready for review October 13, 2026 13:19
@enaboapps
enaboapps merged commit 0dc5d47 into main Oct 13, 2026
6 checks passed
@enaboapps
enaboapps deleted the claude/1041-menu-panels branch October 13, 2026 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use the panel UI for Home and action menus

2 participants