Skip to content

Phase 1: Migrate action buttons to hamburger menu

Overview

Replace the five action buttons (Traffic, USB, Folders, Screenshot, Report) in the status-bar right-to-left layout block with a single egui::menu::menu_button("☰", ...) hamburger menu. Leave the Gaps badge, transient bug-report status message, and all glanceable state (volume, bandwidth, sparklines) untouched.

Parent plan

PLAN-hamburger-menu.md

Current state of the code

The right-to-left layout block lives at ryll/src/app.rs:1518 (ui.with_layout(egui::Layout::right_to_left(...))). Widgets appear in code order, which renders right-to-left on screen:

Code order Widget Lines Type
1 Mute button (🔇/🔊) 1519-1524 Glanceable state
2 Volume slider 1525-1532 Glanceable state
3 Separator 1533 Layout
4 Bandwidth label 1535-1541 Glanceable state
5 Bandwidth sparkline 1542-1567 Glanceable state
6 Separator 1569 Layout
7 Traffic button 1570-1572 Action (toggle)
8 USB button 1573-1575 Action (toggle)
9 Folders button 1576-1578 Action (toggle)
10 Screenshot button 1579-1581 Action (one-shot)
11 Gaps badge 1582-1601 Notification (out of scope)
12 Report button 1603-1608 Action (one-shot)
13 Transient status msg 1610-1616 Status (keep)

Items in bold are the five actions migrating into the menu.

Field names on self used by the action buttons

  • self.show_traffic_viewer: bool (line 319) — Traffic toggle
  • self.show_usb_panel: bool (line 295) — USB toggle
  • self.show_webdav_panel: bool (line 306) — Folders toggle
  • self.show_bug_dialog: bool (line 277) — Report dialog
  • self.bug_report_type: BugReportType (line 278) — Report type
  • self.bug_description: String (line 279) — Report text
  • self.bug_status_message: Option<(String, Instant)> (line 280)

F8 keyboard shortcut

F8 handling is at app.rs:1426-1432, early in the event loop before the status bar renders. It calls self.open_screenshot_dialog() when !self.region_select_active. This wiring is independent of the button and must remain unchanged.

egui menu_button

egui::menu::menu_button is not used anywhere in the codebase today. This will be the first use.

Implementation steps

Step 1: Add the hamburger menu

At app.rs:1570 (immediately after the second separator on line 1569), replace the five action buttons (lines 1570-1608) with a single egui::menu::menu_button call.

The menu must be emitted after the separator at line 1569 (i.e. to the left of the bandwidth sparkline in the right-to-left layout). In egui's right-to-left mode, widgets added later appear further left, so adding the menu here places it between the bandwidth area and the Gaps badge — matching the plan's intent.

Replace lines 1570-1608 with:

egui::menu::menu_button(ui, "☰", |ui| {
    ui.checkbox(&mut self.show_traffic_viewer, "Traffic");
    ui.checkbox(&mut self.show_usb_panel, "USB");
    ui.checkbox(&mut self.show_webdav_panel, "Folders");
    if ui
        .add(egui::Button::new("Screenshot").shortcut_text("F8"))
        .clicked()
    {
        self.open_screenshot_dialog();
        ui.close_menu();
    }
    if ui.button("Report").clicked() {
        self.show_bug_dialog = true;
        self.bug_report_type = BugReportType::Display;
        self.bug_description.clear();
        self.begin_trigger_snapshot();
        ui.close_menu();
    }
});

Key design decisions:

  • Checkboxes for toggles: Traffic, USB, and Folders use ui.checkbox bound directly to their bool fields. The checkbox reflects open/closed state and toggles it on click. No explicit ui.close_menu() — the panel toggles and the user can toggle multiple panels in one menu visit.

  • shortcut_text("F8") on Screenshot: Renders "F8" in subdued text to the right of "Screenshot", per egui convention. This is purely decorative — the actual F8 key handling remains at app.rs:1426.

  • ui.close_menu() on one-shot actions: Screenshot and Report close the menu after triggering, since there's no toggle state to inspect.

  • Report replicates exact existing logic: show_bug_dialog, bug_report_type, bug_description.clear(), and begin_trigger_snapshot() — identical to the removed button at lines 1603-1608.

Step 2: Leave Gaps badge and transient message in place

The Gaps badge (lines 1582-1601) and transient bug-report status message (lines 1610-1616) remain exactly where they are. After Step 1, the widget order becomes:

Code order Widget Type
1 Mute button Glanceable state
2 Volume slider Glanceable state
3 Separator Layout
4 Bandwidth label Glanceable state
5 Bandwidth sparkline Glanceable state
6 Separator Layout
7 Hamburger menu Actions (new)
8 Gaps badge Notification (unchanged)
9 Transient status msg Status (unchanged)

The hamburger icon sits just to the left of the Gaps badge on screen (to the right of the bandwidth area), forming a compact right-side cluster.

Step 3: Verify F8 shortcut is undisturbed

Confirm that the F8 handling at app.rs:1426-1432 is untouched — it must continue to call self.open_screenshot_dialog() independently of the menu. No code change needed; this is a review checkpoint.

Step 4: Update README.md

Lines 22, 28, 29, 30, 31 reference clicking buttons "in the status bar". Update them to use "Menu" phrasing:

Line Current text New text
22 Press F8 or click "Screenshot" in the status bar Press F8 or use Menu -> Screenshot
28 Press F12 or click "Report" Press F12 or use Menu -> Report
29 Press F11 or click "Traffic" Press F11 or use Menu -> Traffic
30 Click "USB" in the status bar Use Menu -> USB
31 Click "Folders" in the status bar Use Menu -> Folders

Do not change the Gaps reference on line 24 — Gaps remains a status-bar button.

Step 5: Update ARCHITECTURE.md

ARCHITECTURE.md references status-bar buttons in several places:

  • Line 549: "USB" status bar button -> Menu -> USB
  • Line 675: "Folders" status bar button -> Menu -> Folders
  • Line 875: clicking the **Report** button in the status bar -> using **Menu -> Report**
  • Line 930: clicking the **Traffic** button in the status bar -> using **Menu -> Traffic**

Step 6: Update AGENTS.md

AGENTS.md has no direct "add new features as status-bar buttons" guidance, but references exist:

  • Line 192: always-visible Gaps: N status-bar — unchanged (Gaps stays)
  • Line 357: always-visible Gaps: N button in the bottom status — unchanged

No changes needed unless the sub-agent finds additional references during implementation.

Step 7: Run validation

pre-commit run --all-files
cargo test --workspace

Fix any rustfmt, clippy, or test failures before considering the phase complete.

Files to modify

File Changes
ryll/src/app.rs Replace five action buttons (lines 1570-1608) with menu_button call
README.md Update five status-bar button references to Menu phrasing
ARCHITECTURE.md Update four status-bar button references to Menu phrasing

Risks and mitigations

  • menu_button API mismatch: egui's menu_button is stable and well-documented. If the import path differs from egui::menu::menu_button, check egui::menu module docs. The function signature is menu_button(ui, title, add_contents).

  • Checkbox auto-close: ui.checkbox in an egui menu does not close the menu by default, which is the desired behaviour for toggles. Verify this in testing — if it auto-closes, wrap in a ui.menu_item_with_response or suppress via ui.set_close_menu_on_click(false).

  • Menu placement: In a right-to-left layout, the menu popup should appear below the button. egui handles this automatically. If the popup is clipped by the window edge, egui will reposition it. No special handling needed.

Success criteria

  • The five action buttons (Traffic / USB / Folders / Screenshot / Report) are no longer in the layout block.
  • A menu_button("☰", ...) is in the layout block with the five entries inside.
  • Side-panel checkboxes reflect open/closed state.
  • F8 still triggers the screenshot flow (unchanged wiring).
  • The Gaps badge and the bug-report transient message are still in the layout block, unchanged.
  • pre-commit run --all-files passes.
  • cargo test --workspace passes.
  • README.md and ARCHITECTURE.md reference Menu instead of status-bar buttons for the five migrated actions.

Sub-agent brief

Effort: medium | Model: sonnet | Isolation: none

Execute Steps 1-7 above in order. The code change is concentrated in ryll/src/app.rs lines 1570-1608 — replace those lines with the menu_button block from Step 1. Then update documentation per Steps 4-5. Run validation per Step 7.

📝 Report an issue with this page