# TMenuView  (guide pp. 482–485)

Rust module(s): `src/menu/menu_view.rs`, `src/menu/menu_session.rs`, `src/menu/mod.rs`   |   magiblot: `include/tvision/menus.h` / `source/tvision/tmnuview.cpp`

> TMenuView is the abstract base from which TMenuBar and TMenuBox derive.
> In tvision-rs it is split: the shared data lives in `MenuViewState`,
> the shared passive behaviour in free functions (`hot_key`, `update_menu_commands`,
> `handle_event`), the shared interface in the `MenuView` trait, and the
> interactive modal loop in `MenuSession` (deviation D9).

| Guide entry | Pg | Bucket | Corr | Rust symbol / mapping | Doc | Notes |
|---|---|---|---|---|---|---|
| `parentMenu` (field) | 483 | EQUIVALENT | OK | Level stack in `MenuSession` (no field on `MenuViewState`) | N/A | Guide: pointer to the parent menu view for hierarchical navigation. Rust replaces the up-pointer with a `Vec<MenuLevel>` stack inside `MenuSession`; the parent-of relationship is encoded by stack position, not a field on the view. Deviation D3 (pointer → session stack), documented in `menu_view.rs` module doc and `menu_session.rs` module doc. Private / internal; N/A for doc score. |
| `menu` (field) | 483 | PORTED | OK | `MenuViewState::menu: Menu` | 3 | Guide: points to the TMenu record for this view. Rust: `pub menu: Menu` on `MenuViewState`. Doc now covers what it holds, that the session clones it at activation (so in-place mutations during an open session are invisible), and how to update between sessions. |
| `current` (field) | 483 | EQUIVALENT | OK | `MenuViewState::current: Option<usize>` (index, not pointer) | 3 | Guide: `PMenuItem` pointer to the currently selected item. Rust: `Option<usize>` index into `menu.items`. Doc now covers the index convention, that `MenuSession` writes it through `View::set_menu_current` on every navigation step, and that callers should not write it while a session is active. |
| `Init` (constructor) | 483 | PORTED | OK | `MenuViewState::new` + `MenuBar::new` / `MenuBox::new` | 3 | Guide: calls `TView.Init`, sets `eventMask |= evBroadcast`. Rust: `MenuViewState::new` builds state; the broadcast mask opt-in is not ported — the group fans broadcasts unconditionally. The `new` doc now explicitly mentions the broadcast deviation. |
| `Load` (constructor) | 483 | NOT-PORTED | — | — | — | TStreamable stream persistence. Dropped codebase-wide (deviation D12, `TStreamable` dropped). |
| `Execute` (method) | 483 | EQUIVALENT | OK | `MenuSession` capture handler (`menu_session.rs`) | 3 | Guide: runs the interactive menu modal loop, returns the chosen command. Rust: flattened into one `MenuSession` `CaptureHandler` on the single event loop (deviation D9). Module doc of `menu_session.rs` is comprehensive: architecture, state, keyboard, mouse, context popups — scores 3. |
| `FindItem` (method) | 484 | PORTED | OK | `menu_view::matching_item` + `menu_session` plain-hotkey arm | N/A | `pub(crate)` — not held to the public doc bar. |
| `GetItemRect` (method) | 484 | PORTED | OK | `MenuView::get_item_rect` (trait method, default `Rect::new(0,0,0,0)`) | 3 | Guide: abstract — descendants must override. Rust: default in the `MenuView` trait returns an empty rect; doc now explicitly states every concrete implementor must override it, and explains the cell-for-cell agreement requirement with the draw layer so mouse hit-testing is correct. |
| `GetHelpCtx` (method) | 484 | PORTED | OK | `MenuSession::help_ctx` + `CaptureHandler::menu_help_ctx` + `CaptureStack::active_menu_help_ctx` | 3 | Guide: walks the `parentMenu` chain from the active (deepest) level toward the bar; stops at the first level whose `current` item is named and has `helpCtx != hcNoContext`; returns that item's `helpCtx`. Rust: `MenuSession::help_ctx()` performs the equivalent walk over `self.levels` from top to bottom (the level stack replaces the `parentMenu` chain, deviation D3/D9). The status-line refresh in `Program::pump_once` calls `CaptureStack::active_menu_help_ctx()`, which finds the live `MenuSession` via `CaptureHandler::menu_help_ctx()` and returns its result; this fires before the normal `top_modal_view` path so per-item help context reaches the status line while a menu is open. Three unit tests in `menu_session.rs` verify the walk: highlighted item with context, fallback cases (no highlight, NO_CONTEXT item, separator), and deepest-level-wins ordering. |
| `GetPalette` (method) | 484 | EQUIVALENT | OK | `MenuColors::resolve(ctx)` reading `Role::Menu*` from `Theme` | 3 | Guide: returns `CMenuView` palette (6 entries, palette indices 1–6 mapping to app palette slots 2–7). Rust: `MenuColors::resolve` reads the six `Role::Menu*` values from the draw context's theme. Doc now covers what it does, when to call it (once at start of `draw`, reuse per item), and notes the theme-level chain derivation. |
| `HandleEvent` (method) | 484 | EQUIVALENT | OK | `menu_view::handle_event` (passive half) + `MenuSession` (interactive half) | 3 | Guide: handles mouse, keyboard (hotkeys + Alt-shortcuts), and `cmCommandSetChanged`. Rust splits this: passive (`cmCommandSetChanged`, accelerator post, bar activation) lives in `menu_view::handle_event`; the full interactive navigation lives in `MenuSession`. Deviation D9, documented thoroughly in both module docs. Each branch is individually commented against the C++ source with line references. Score 3. |
| `HotKey` (method) | 484 | PORTED | OK | `menu_view::hot_key(menu, key) -> Option<Command>` | 3 | Guide: returns the item associated with a hot key, nil if not found or disabled. Rust: `hot_key` walks the tree recursively, skips separators, recurses into submenus, returns `None` for missing or disabled. Doc covers what (recursive walk), how (depth-first, skips disabled/separator), and heritage. Four unit tests verify the contract. Score 3. |
| `NewSubView` (method) | 485 | EQUIVALENT | OK | `MenuSession` level-push opens a `MenuBox` inline | 2 | Guide: constructs a new `TMenuBox` for a submenu. Rust: the session's level-push path creates the box geometry via `menu_box_rect` and pushes a `MenuLevel` — no dedicated symbol. No dedicated public symbol exists to raise; N/A beyond the architectural note. |
| `Store` (method) | 485 | NOT-PORTED | — | — | — | TStreamable persistence. Dropped codebase-wide (deviation D12). |
| `CMenuView` palette (6 entries) | 485 | EQUIVALENT | OK | `tv::theme::Role::MenuNormal`, `MenuNormalShortcut`, `MenuSelected`, `MenuSelectedShortcut`, `MenuDisabled`, `MenuSelectedDisabled` | 3 | Guide: `CMenuView` maps indices 1–6 to app palette slots 2–7. Rust: six `Role::Menu*` variants documented in `src/theme.rs` (theme pass) with full chain, color, and `MenuBar`/`MenuBox`/`MenuColors` consumer for each. |
| `putClickEventOnExit` (private field) | — | EQUIVALENT | OK | `MenuSession::put_click_event_on_exit: bool` | N/A | Not in guide (private field in magiblot). Session field controls exit-click re-post for bar/box vs popup. Documented in `menu_session.rs`. N/A (internal). |

## Summary

- PORTED: 6   EQUIVALENT: 8   NOT-PORTED: 2   MISSING: 0   UNSURE: 0
- SUSPECT: 0   |   doc<3 (public): 0   |   → concept: 0
- Raised to score 3: `MenuViewState::menu`, `MenuViewState::current`, `MenuViewState::new`, `MenuView::get_item_rect`, `MenuColors::resolve`. `CMenuView palette roles` raised to 3 in the theme.rs Role pass (documented in `src/theme.rs`). `matching_item` is `pub(crate)` — N/A. `NewSubView` has no dedicated public symbol — architectural note only.
