# TWindow  (guide pp. 577–581)

Rust module(s): `src/window/window.rs`, `src/window/mod.rs`   |   magiblot: `include/tvision/views.h` (TWindow) + `source/tvision/twindow.cpp`

> TWindow is a specialised TGroup that builds a TFrame around itself,
> owns decoration flags, a number, a palette selector, a title, and a zoom
> rect. The guide documents 6 fields, 9 methods (Init/Load/Done/Close/
> GetPalette/GetTitle/HandleEvent/InitFrame/SetState/SizeLimits/
> StandardScrollBar/Store/Zoom — see rows below), and 3 palette strings
> (cpBlueWindow / cpCyanWindow / cpGrayWindow) with 8 entries each.

| Guide entry | Pg | Bucket | Corr | Rust symbol / mapping | Doc | Notes |
|---|---|---|---|---|---|---|
| `Flags` (field, `uchar`, wfMove/wfGrow/wfClose/wfZoom) | 578 | EQUIVALENT | OK | `tv::WindowFlags` struct-of-bools (`r#move`, `grow`, `close`, `zoom`) | 3 | D5 flag-word → struct-of-bools. Type doc now explains the `r#move` raw-identifier spelling, shows a usage example (disable zoom), and documents the push-down relationship to Frame — score 3. |
| `Frame` (field, `PFrame`, pointer to the frame child) | 578 | EQUIVALENT | OK | `tv::Window::frame_id: ViewId` | 3 | D3 push-down. `frame_id()` doc now explains why a `ViewId` replaces a raw pointer and how callers use `child_mut` + downcast to reach the frame without an upward parent reference — score 3. |
| `Number` (field, `Integer`, 1–9 selectable window number) | 578 | PORTED | OK | `tv::Window::number: i16` (private); exposed via `View::number() -> Option<i16>` | 3 | `View::number()` override doc now explains Alt-N selection: `program_handle_event` broadcasts `cmSelectWindowNum` → `Desktop::select_window_num` → `Group::focus_by_number` matches on `View::number()` — score 3. |
| `Palette` (field, `Integer`, wpBlueWindow/wpCyanWindow/wpGrayWindow) | 578 | EQUIVALENT | OK | `tv::WindowPalette` enum (`Blue`/`Cyan`/`Gray`) + `tv::Window::palette: WindowPalette` | 3 | `WindowPalette` doc now gives when-to-choose guidance for all three variants and names the corresponding `Role` families. `palette()` getter doc links to WindowPalette and explains read vs change — score 3. |
| `Title` (field, `PString`) | 578 | PORTED | OK | `tv::Window::title: Option<String>` | 3 | `title()` getter doc now covers construction, rename via `set_title`, truncation responsibility in the frame, and the `None` = untitled mapping — score 3. |
| `ZoomRect` (field, `TRect`, saved unzoomed bounds) | 578 | PORTED | OK | `tv::Window::zoom_rect: Rect` | 3 | `zoom_rect()` doc now explains the toggle mechanic (saved on first zoom, restored on un-zoom, equals initial bounds at construction) — score 3. |
| `Init` (constructor) | 579 | PORTED | OK | `tv::Window::new(bounds: Rect, title: Option<String>, number: i16) -> Window` | 3 | C++ Init: sets `sfShadow`, `ofSelectable + ofTopSelect`, `gfGrowAll + gfGrowRel`, sets Title/Number/Flags, calls `InitFrame` + inserts frame, sets ZoomRect. Rust `new` matches every step verbatim (verified in `new_ports_ctor_defaults` test). Doc comment enumerates all defaults explicitly — score 3. |
| `Load` (streaming constructor) | 579 | NOT-PORTED | — | — | N/A | TStreamable / stream I/O is dropped project-wide (CLAUDE.md locked decision: "TStreamable dropped; serde if revived"). No counterpart. |
| `Done` (destructor) | 579 | NOT-PORTED | — | — | N/A | Pascal/C++ explicit destructor chain. Rust `Drop` on the embedded `Group` reclaims children automatically; no explicit `Done` needed. |
| `Close` (method) | 579 | PORTED | OK | `tv::Window::handle_event` — close-command arm calls `ctx.request_close(id)` | 2 | C++ `close()` calls `valid(cmClose)` then `destroy(this)`. Rust: handle_event close arm calls `self.valid(cmClose, ctx)` then `ctx.request_close(id)` — same logic. There is no standalone public `close()` method; the logic is embedded in `handle_event` (score 3). Structurally blocked at 2 for this row: no public entry point exists to score independently, and creating one would be a code/behavior change outside the rustdoc-only scope. |
| `GetPalette` (method) | 579 | EQUIVALENT | OK | `tv::Window::palette() -> WindowPalette` + `tv::Frame::set_palette` + `Role` mapping | 3 | `palette()` getter doc now includes when-to-use guidance and links to `WindowPalette` for the full Role-family mapping — score 3. |
| `GetTitle` (method) | 579–580 | PORTED | OK | `tv::Window::title() -> Option<&str>` + `tv::Frame` calls `owner.get_title()` push-down via `Frame::set_title` | 3 | `title()` doc now covers construction, rename, frame truncation, and `None` = untitled — score 3. |
| `HandleEvent` (method) | 580 | PORTED | OK | `tv::Window::handle_event` (impl `View::handle_event`) | 3 | C++ handles: `cmResize` (if wfMove/wfGrow), `cmClose` (if wfClose, with modal-cancel path), `cmZoom` (if wfZoom), `kbTab`/`kbShiftTab`, and broadcast `cmSelectWindowNum` (matches `Event.infoInt == number`). Rust: resize → `KeyboardResizeCapture`; close + modal cancel; zoom → `Window::zoom`; Tab/Shift+Tab. `cmSelectWindowNum` is re-architected: moved to `program_handle_event` + `Desktop::select_window_num` + `Group::focus_by_number` (skip-listed on the `#[delegate]` macro). This is a documented, deliberate deviation (module doc + `handle_event` doc comment). The handle_event doc comment is comprehensive and enumerates each arm — score 3. |
| `InitFrame` (static factory method) | 580 | NOT-PORTED | — | — | N/A | C++ `TWindow::initFrame(TRect)` is a static factory that creates the `TFrame`; `TWindowInit` stores a `createFrame` function pointer so subclasses can inject a custom frame type. Rust `Window::new` constructs `Frame::new` directly and inserts it; no injection hook exists. Module doc notes: "A custom-frame injection hook has no consumer yet; reintroduce it when a subtype needs a non-default frame." Intentionally absent, with documented rationale. |
| `SetState` (method) | 580 | PORTED | OK | `tv::Window::set_state` (impl `View::set_state`) | 3 | C++: calls `TGroup::setState`, then if `sfSelected` calls `setState(sfActive, enable)` on both group and frame directly, then enables/disables cmNext/cmPrev/cmResize/cmClose/cmZoom. Rust matches exactly: calls `group.set_state`, then calls `group.set_state(Active, enable)` (which propagates to children incl. the frame via Group's propagation), then enables/disables the same command set. The `set_state` doc comment explains every arm including the command-enable logic — score 3. |
| `SizeLimits` (method) | 580 | PORTED | OK | `tv::Window::size_limits` (impl `View::size_limits`) | 3 | `size_limits` doc now explains the 16×6 floor AND the `calc_bounds` skip-list rationale (why `calc_bounds` is NOT delegated to the group — it must route through the window's `size_limits` to enforce the floor on owner-driven resizes) — score 3. |
| `StandardScrollBar` (method) | 580–581 | PORTED | OK | `tv::Window::standard_scroll_bar(opts: ScrollBarOptions) -> ViewId` | 3 | Method doc now specifies the exact cell geometry for both orientations ("fits inside the frame without covering corners"), the call-before-show pattern, and how to wire the returned id to a scroller — score 3. |
| `Store` (streaming write) | 581 | NOT-PORTED | — | — | N/A | TStreamable / stream I/O dropped project-wide (same as `Load`). |
| `Zoom` (method) | 581 | PORTED | OK | `tv::Window::zoom` (private method, called from `handle_event`) | N/A | C++ `zoom()`: calls `sizeLimits`, if `size != maxSize` saves `zoomRect = getBounds()` then `locate(0,0,max.x,max.y)`, else `locate(zoomRect)`. Rust matches exactly. Method is private; `handle_event` doc covers it. No public entry to score. |
| `cpBlueWindow` palette (8 entries: indices 1–8 as listed in `twindow.cpp` header comment) | 581 | EQUIVALENT | OK | `tv::WindowPalette::Blue` → `Role::FramePassive`, `Role::FrameActive`, `Role::FrameIcon`, `Role::ScrollBarPage`, `Role::ScrollBarControl`, `Role::ScrollerNormal`, `Role::ScrollerSelected`, reserved | 3 | `WindowPalette` doc now names the role families for each variant and explains the 8-entry indexed palette → named `Role` mapping — score 3. |
| `cpCyanWindow` palette (8 entries, indices 16–23) | 581 | EQUIVALENT | OK | `tv::WindowPalette::Cyan` → `Role::FrameCyan*` family | 3 | Covered by updated `WindowPalette` doc — score 3. |
| `cpGrayWindow` palette (8 entries, indices 24–31) | 581 | EQUIVALENT | OK | `tv::WindowPalette::Gray` → `Role::FrameGray*` family | 3 | Covered by updated `WindowPalette` doc — score 3. |
| `TTitleStr` type (`string[80]`) | 557 | NOT-PORTED | — | — | N/A | Pascal fixed-length string type used to type title fields. Rust uses `Option<String>` (heap-allocated, unbounded). No counterpart needed — the type was purely a Pascal/Borland constraint. |
| `TWindowInit` mixin (createFrame function pointer) | C++ only | NOT-PORTED | — | — | N/A | C++ multiple-inheritance mixin carrying the `createFrame` factory pointer. Not in the guide directly; surfaced by `initFrame` NOT-PORTED above. No Rust counterpart. |
| `wfMove / wfGrow / wfClose / wfZoom` flag constants | 578 | EQUIVALENT | OK | `tv::WindowFlags` fields `r#move`, `grow`, `close`, `zoom` | N/A | D5: flag word → struct-of-bools. Values match the C++ bit positions semantically; no separate constants exist. |
| `wpBlueWindow / wpCyanWindow / wpGrayWindow` palette constants | 578 | EQUIVALENT | OK | `tv::WindowPalette::Blue`, `Cyan`, `Gray` | N/A | Integer constants replaced by the `WindowPalette` enum — same three values, type-safe. |
| `wnNoNumber` constant | C++ only | EQUIVALENT | OK | `Window::new(…, 0)` → `View::number()` returns `None` | N/A | The sentinel `0` maps to `None` in `View::number()`; documented in the `number_to_option` helper comment. |

## Summary

- PORTED: 11   EQUIVALENT: 10   NOT-PORTED: 6   MISSING: 0   UNSURE: 0
- SUSPECT: 0   |   doc<3 (public): 1   |   → concept: 0
- Notable finding: No correctness gaps or SUSPECT items. The most architecturally significant deviation is `cmSelectWindowNum` handling: C++ does it inline in `TWindow::handleEvent` (matching on `event.message.infoInt == number`), but Rust moves the whole mechanism to `program_handle_event` + `Desktop::select_window_num` + `Group::focus_by_number` — the window's `select_window_num` method is in the `#[delegate(skip(…))]` list and the `handle_event` doc comment explains why. This is correct and deliberate, but it is the one place where a reader looking for the C++ broadcast-handler will not find it in the Window at all.
- Rustdoc sweep: 12 below-bar rows raised to score 3 (WindowFlags, frame_id, number, WindowPalette/palette, title, zoom_rect, GetPalette, GetTitle, size_limits, StandardScrollBar, cpBlue/Cyan/Gray palette). 1 row remains at 2 (Close/`close()`) — structurally blocked: no public `close()` method exists, the logic is embedded in `handle_event` (score 3), and adding a standalone method would be a code change outside the rustdoc-only scope. No theme.rs edits needed (all Role references are in `window.rs` `WindowPalette` doc). No → concept rows present.
