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>
5.8 KiB
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
-
Den Control-Menü-Zustand von der Menüleiste trennen:
control_menuträgt die Auswahl selbst (z. B.Option<usize>für den gewählten Eintrag) stattmenu = Some((0, 0))zu missbrauchen.menubleibt 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. -
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 Fensterrechteckself.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 beideCommand::ControlMenuausführen. Kein fensterartspezifischer Sonderfall. -
Anheftregel bei Platzmangel, in dieser Reihenfolge: (a) Passt die Popup-Höhe nicht zwischen
rect.y + 1und die Statuszeile, klappt das Popup nach oben: Popup-Unterkante =rect.y - 1, Popup-y =rect.y - Höhe. Minimierte Fenster liegen lautrect()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, dassx + Breite <= area.right(); da die Breite größer als drei Zellen ist, bleibt die Symbolspalterect.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. -
Zeichenreihenfolge: Das Popup wird nach allen Fenstern und vor der Statuszeile mit
Cleargezeichnet, so wie heute die Menüleisten-Popups; es überdeckt Fensterinhalt lokal, nicht die Menüleiste. -
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.
-
Nachweis über TestBackend für mehrere Fensterarten (mindestens Code, Project, Output, Immediate): Nach Alt+Minus und
drawwird geprüft, dass der Rahmen des Popups in Zeilerect.y + 1ab Spalterect.xbeginnt, dass die Zelle „File“ in Zeile 0 den normalen Menüstil trägt, dass bei einem minimierten Fenster (Ctrl+F9) die Popup-Unterkante inrect.y - 1liegt und die linke Spalterect.xist, dass ein per Ctrl+F7 an den rechten Rand verschobenes Fenster ein Popup mitx + Breite <= area.right()undx <= rect.xerhält, und dass nach Ctrl+F10 (Maximize) das Popup unter der Titelzeile des maximierten Rechtecks liegt. Keine rein textuellen Snapshots. -
Nebenbefunde der Windows-Testausführung werden im selben Change behoben, ohne die Fensterlogik zu berühren:
prepare_publicationöffnet die Temporärdatei vorsync_allschreibend;relative_pathschreibt Verweise immer mit/, weil\unter Linux/macOS kein Trenner ist und beide Plattformen/auflösen; zeilenendenabhängige Testvergleiche normalisieren CRLF. Details und Zahlen inevidence/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 Hilfsfunktionmenu_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.mdum 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.