## Context `App` hält ein einziges Menüfeld `menu: Option<(usize, usize)>` für die Menüleiste (Menüindex, Eintrag) und ein Flag `control_menu: bool`. `Command::ControlMenu` setzt `control_menu = true` und `menu = Some((0, 0))`. Dadurch gilt in `render.rs` der Menüleistentitel mit Index 0 („File“) als ausgewählt und wird hervorgehoben. Der Aufklappbereich wird in `render.rs` mit `Rect::new(x, 1, …)` gezeichnet; `x` ist bei Control-Menü nur die linke Fensterkante, `y` ist fest die Zeile unter der Menüleiste. Das Popup steht deshalb nicht am `[≡]`-Symbol des Fensters, sondern wandert an den oberen Bildschirmrand und überdeckt fremde Fenster. Die Tastenverteilung im Menüzustand blockiert Links/Rechts, wenn `control_menu` gesetzt ist, erlaubt aber Alt+Mnemonic-Wechsel in die Menüleiste. Der Hit-Bereich für `[≡]` existiert bereits nur für das aktive Fenster (`Hit::Command(Command::ControlMenu)` auf `Rect::new(rect.x, rect.y, 3, 1)`). Beobachtung aus der Validierung: siehe `evidence/befund-2026-09-08.md`. ## Goals / Non-Goals **Goals:** Control-Menü als fensterlokales Popup am Symbol; keine sichtbare oder logische Kopplung an einen Menüleistentitel; bestehende Tasten- und Mausbedienung unverändert; prüfbare Renderposition. **Non-Goals:** Neues Menüsystem, Änderung der Menüleisten-Aufklappposition, neue Befehle im Control-Menü, Control-Menü für inaktive Fenster, Änderung des Themes. ## Decisions 1. Den Control-Menü-Zustand von der Menüleiste trennen: `control_menu` trägt die Auswahl selbst (z. B. `Option` für den gewählten Eintrag) statt `menu = Some((0, 0))` zu missbrauchen. `menu` bleibt bei offenem Control-Menü `None`. Damit hebt die Menüleiste nichts hervor, ohne dass der Renderer Sonderfälle braucht. Die gemeinsame Tastenlogik (Auf/Ab, Enter, Mnemonic, Esc) wird über eine kleine Abstraktion „offene Liste“ geteilt, die beide Zustände bedient; keine zweite Kopie der Eintragsnavigation. 2. Eine einzige Platzierungsfunktion für alle `WindowKind`-Varianten (Code, Project, Output, Immediate, Debug, Calls, Help, Toolbox, Palette, MenuDesign). Ankerpunkt ist die Zelle des `[≡]`-Symbols im aktuellen Fensterrechteck `self.rect(w)`: Popup-x = `rect.x`, bevorzugt Popup-y = `rect.y + 1` (erste Zeile unter der Titelzeile). Das gilt für Normal, Maximized (Rechteck = Arbeitsfläche) und Minimized (Titelzeile des minimierten Fensters am unteren Rand). Bei Alt+Minus und Mausklick identisch, da beide `Command::ControlMenu` ausführen. Kein fensterartspezifischer Sonderfall. 3. Anheftregel bei Platzmangel, in dieser Reihenfolge: (a) Passt die Popup-Höhe nicht zwischen `rect.y + 1` und die Statuszeile, klappt das Popup nach oben: Popup-Unterkante = `rect.y - 1`, Popup-y = `rect.y - Höhe`. Minimierte Fenster liegen laut `rect()` immer zwei Zeilen über der Statuszeile und treffen damit stets diesen Fall. (b) Passt es auch oben nicht vollständig, wird die Richtung mit mehr Platz gewählt und die vorhandene Scroll-Logik für Einträge greift; die Titelzeile des eigenen Fensters wird nie überdeckt. (c) Ragt es rechts hinaus, wird x nur so weit reduziert, dass `x + Breite <= area.right()`; da die Breite größer als drei Zellen ist, bleibt die Symbolspalte `rect.x..rect.x+3` überdeckt. Die visuelle Verbindung zum Symbol bleibt in allen Fällen: eine Popup-Kante grenzt an die Titelzeile, und die Symbolspalte liegt innerhalb der Popup-Breite. 4. Zeichenreihenfolge: Das Popup wird nach allen Fenstern und vor der Statuszeile mit `Clear` gezeichnet, so wie heute die Menüleisten-Popups; es überdeckt Fensterinhalt lokal, nicht die Menüleiste. 5. Alt+Mnemonic aus dem offenen Control-Menü wechselt weiterhin in die Menüleiste (bestehendes Verhalten); dabei wird das Control-Menü geschlossen. Links/Rechts bleiben im Control-Menü ohne Wirkung. Esc schließt das Control-Menü, der Fokus bleibt im Fenster, die Statuszeile zeigt die Fensterkürzel. 6. Nachweis über TestBackend für mehrere Fensterarten (mindestens Code, Project, Output, Immediate): Nach Alt+Minus und `draw` wird geprüft, dass der Rahmen des Popups in Zeile `rect.y + 1` ab Spalte `rect.x` beginnt, dass die Zelle „File“ in Zeile 0 den normalen Menüstil trägt, dass bei einem minimierten Fenster (Ctrl+F9) die Popup-Unterkante in `rect.y - 1` liegt und die linke Spalte `rect.x` ist, dass ein per Ctrl+F7 an den rechten Rand verschobenes Fenster ein Popup mit `x + Breite <= area.right()` und `x <= rect.x` erhält, und dass nach Ctrl+F10 (Maximize) das Popup unter der Titelzeile des maximierten Rechtecks liegt. Keine rein textuellen Snapshots. 7. Nebenbefunde der Windows-Testausführung werden im selben Change behoben, ohne die Fensterlogik zu berühren: `prepare_publication` öffnet die Temporärdatei vor `sync_all` schreibend; `relative_path` schreibt Verweise immer mit `/`, weil `\` unter Linux/macOS kein Trenner ist und beide Plattformen `/` auflösen; zeilenendenabhängige Testvergleiche normalisieren CRLF. Details und Zahlen in `evidence/befund-2026-09-08.md`. ## Risks / Trade-offs - Trennung des Zustands berührt alle Stellen, die `self.menu.is_some()` als „ein Menü ist offen“ lesen (Tasten- und Mausverteilung) → gezielt in eine Hilfsfunktion `menu_open()` zusammenführen, damit Klick außerhalb und Esc beide Zustände schließen. - Bei sehr kleinem Terminal passt das Popup weder unter noch über die Titelzeile → Richtung mit mehr Platz und vorhandene Eintrags-Scroll-Logik; das eigene Symbol bleibt sichtbar, ein Teil der Einträge ist dann nur per Auf/Ab erreichbar. - Hilfe-Referenz und Tutorial nennen Alt+Minus, aber keinen Ort → Abschnitt 2 der `ide-referenz.md` um einen Satz ergänzen, keine Änderung der Hilfeseiten nötig. ## Migration Plan Keine Datenmigration. Änderung in `app.rs`, `render.rs`, Test in `tests/app.rs`, ein Satz in `docs/ide-referenz.md`. Rücknahme durch Revert des Commits; keine gespeicherten Zustände betroffen.