diff --git a/docs/superpowers/specs/2026-07-15-auto-hide-caption-design.md b/docs/superpowers/specs/2026-07-15-auto-hide-caption-design.md new file mode 100644 index 0000000..7d9499e --- /dev/null +++ b/docs/superpowers/specs/2026-07-15-auto-hide-caption-design.md @@ -0,0 +1,90 @@ +# Auto-Hide Caption (frame visible only when active) — Design + +**Date:** 2026-07-15 +**Status:** Approved (brainstorming) + +## Goal + +Show the calculator window's title bar and close button **only while the window is +active**. When focus moves to another window the calculator stays on top as a clean, +chromeless display (no caption, no X); clicking it back (or showing it from the tray) +brings the frame back. + +## Behavior + +- Handle `WM_ACTIVATE` in `CCalculatorWindow`: + - **Activated** (`WA_ACTIVE` / `WA_CLICKACTIVE`): add `WS_CAPTION | WS_SYSMENU`. + - **Deactivated** (`WA_INACTIVE`): remove `WS_CAPTION | WS_SYSMENU`. +- The toggle uses `SetWindowLongPtr(GWL_STYLE)` followed by + `SetWindowPos(SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER)`. +- `CreateStandalone` is unchanged (window is created with the caption styles; it is + hidden at that point, so the first activation just confirms the state). +- A private helper `ApplyFrameStyle(bool visible)` centralizes the style/geometry change; + a `bool m_captionVisible` member tracks the current state and makes the call idempotent + (no-op when the requested state already applies). + +## Geometry — display stays put + +When the frame toggles, the **client rectangle keeps its exact screen position**: the +caption grows upward when it appears and retracts when it disappears; the displayed +number never moves. + +- On toggle: take the current client rect in screen coordinates + (`GetClientRect` + `ClientToScreen`), compute the new window rect for the new style + with `AdjustWindowRectEx`, and pass position + size to the same `SetWindowPos` call + that applies `SWP_FRAMECHANGED`. +- Safety clamp: if growing upward would push the window top above the work area top, + clamp to the work area (in practice the window sits near the taskbar, so this is a + guard, not an expected path). + +## Position persistence — canonical form + +`OnExitSizeMove` currently saves the window's top-left corner, which now depends on +whether the caption is present (± caption height). To keep the restored position stable +across restarts regardless of the frame state at save time: + +- **Save** the position in canonical form: the top-left of the **chromeless** window + (equal to the client origin, since a plain `WS_POPUP` window has no frame offset). +- **Restore** (`PlaceInitial`) converts the canonical point back to the window origin for + the style in effect at that moment (via `AdjustWindowRectEx`): since the window is + created with the caption styles, its top-left is placed one caption height above the + saved client origin, so the client lands exactly where it was saved. +- Registry value name and type are unchanged (`REG_DWORD` pair via `Settings`); existing + saved positions are reinterpreted with at most a caption-height offset once, then + stay stable. + +## Accepted side effects + +- Opening the tray menu or the About dialog deactivates the calculator, so the caption + disappears while they are open. Consistent with the rule ("active = framed"); no + functional impact. +- The frame appears/disappears instantly (no animation); with DWM on Windows 11 the + repaint is near-imperceptible. + +## Components touched + +`CalculatorWindow.h` / `CalculatorWindow.cpp` only: + +- `MESSAGE_HANDLER(WM_ACTIVATE, OnActivate)` + `OnActivate` implementation. +- Private `void ApplyFrameStyle(bool visible)` + `bool m_captionVisible`. +- Canonical-position adjustment in `OnExitSizeMove` and `PlaceInitial`. + +Engine (`calc`), `Settings` storage format, `App.cpp`, tray icon, and packaging are all +untouched. + +## Testing + +- **Engine regression:** `tests\build-and-run.cmd` still passes 16/16 (feature is UI-only). +- **Manual verification checklist:** + 1. Show from tray → window appears with caption + X. + 2. Click another app → caption disappears; the number display does not move. + 3. Click the calculator → caption reappears; display does not move. + 4. X → hides to tray (existing `WM_CLOSE` behavior). + 5. Drag by caption and by body both work; position persists. + 6. Restart the app → window reappears at the same visual position (no drift). + +## Out of scope (YAGNI) + +- Animated caption transitions. +- Custom-drawn caption (approach B — fallback if the native toggle disappoints). +- Any change to sizing, fonts, or engine behavior.