Files
Chili Palmer 5a1a284505 Phase 6-07a: Fensterlokale Control-Menüs und Windows-Testkorrekturen
Control-Menüs öffnen für alle Fensterarten am [≡]-Symbol des aktiven
Fensters: eigener Auswahlzustand statt Kopplung an die Menüleiste,
bevorzugt unter der Titelzeile, bei Platzmangel nach oben aufgeklappt,
am rechten Rand nur so weit nach links wie nötig. Regressionstest über
TestBackend für Code-, Projekt-, Output-, Immediate-, Debug- und
Hilfefenster, maximiert, minimiert, Rand und Maus.

Nebenbefunde der Windows-Testausführung: Temporärdatei vor sync_all
schreibend öffnen (Zugriff verweigert), relative Projektverweise immer
mit / schreiben, zeilenendenneutrale Vergleiche in Referenzmatrix-,
Kompatibilitäts- und MAK-Beispieltests, DriveListBox-Zeichenbild
plattformneutral. Korpus-Sollausgaben per .gitattributes auf LF.

Specs ide-oberflaeche und ide-projekte synchronisiert, Change archiviert.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 11:02:40 +02:00

35 lines
5.8 KiB
Markdown

## 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<usize>` 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.