Phase 4: Steuerelemente implementieren

This commit is contained in:
2026-09-05 12:49:46 +02:00
parent 1cb6ae8fd9
commit 19804e0e2d
36 changed files with 6472 additions and 689 deletions

View File

@@ -0,0 +1,140 @@
# forms-steuerelemente Specification
## Purpose
Die Steuerelemente machen ein Formular bedienbar: sie stellen sich im
Textbildschirm dar, nehmen Tastatur und Maus entgegen, führen Fokus und
Tabreihenfolge, tragen die Menüleiste und stellen die vordefinierten
Dialoge bereit.
## Requirements
### Requirement: Darstellung im Zellenpuffer
Steuerelemente SHALL sich im vorhandenen Textbildschirm darstellen; es
MUST NOT eine zweite Zeichenschicht neben ihm entstehen. Jede Klasse
SHALL die in der Forms-Referenz festgelegte Optik für die Zustände
normal, fokussiert und deaktiviert zeigen. Der CommandButton SHALL seine
Darstellung nach der Höhe wählen: eine Zeile als `<Text>`, zwei Zeilen
mit einzeiligem Rahmen, ab drei Zeilen als Kasten. Überlappen
Steuerelemente, SHALL die festgelegte Z-Reihenfolge entscheiden, welches
sichtbar ist.
#### Scenario: Schaltfläche nach Höhe
- **WHEN** ein CommandButton mit `Height = 1` und `Caption = "OK"` gezeichnet wird
- **THEN** erscheint im Zellenpuffer `<OK>`
#### Scenario: Deaktivierter Zustand
- **WHEN** ein Steuerelement `Enabled = 0` trägt
- **THEN** unterscheidet sich seine Darstellung sichtbar vom aktiven Zustand und es nimmt keinen Fokus an
### Requirement: Fokus, Tabreihenfolge und Access-Keys
Der Fokus SHALL mit Tab in aufsteigender `TabIndex`-Folge und mit
Umschalt-Tab rückwärts wechseln; Elemente mit `TabStop = 0` oder
`Enabled = 0` MUST übersprungen werden. Ein `&` im Text SHALL den
folgenden Buchstaben zum Access-Key machen, der mit Alt das Element
auslöst oder ihm den Fokus gibt. Enter SHALL die `Default`-Schaltfläche
auslösen, Esc die `Cancel`-Schaltfläche. Fokuswechsel MUST `LostFocus`
am alten und `GotFocus` am neuen Element auslösen, in dieser Reihenfolge.
#### Scenario: Tab überspringt
- **WHEN** das mittlere von drei Elementen `TabStop = 0` trägt und Tab gedrückt wird
- **THEN** erhält das dritte Element den Fokus
#### Scenario: Access-Key
- **WHEN** eine Schaltfläche `Caption = "&OK"` trägt und Alt+O gedrückt wird
- **THEN** wird ihr `Click`-Ereignis ausgelöst
#### Scenario: Reihenfolge der Fokusereignisse
- **WHEN** der Fokus von `Text1` auf `Text2` wechselt
- **THEN** läuft erst `Text1_LostFocus`, danach `Text2_GotFocus`
### Requirement: Maussteuerung mit Trefferprüfung
Ein Mausereignis SHALL dem obersten Steuerelement an seiner Position
zugestellt werden; liegt dort keines, dem Formular. Klick, Doppelklick
sowie `MouseDown`, `MouseMove` und `MouseUp` SHALL mit Taste,
Umschaltzustand und Position in Zellen zugestellt werden. Bei
`DragMode = 1` SHALL das Ziehen automatisch beginnen; `DRAG action%`
SHALL es manuell beginnen, ablegen oder abbrechen, mit `DragOver` und
`DragDrop` am Ziel.
#### Scenario: Treffer nach Z-Reihenfolge
- **WHEN** zwei Steuerelemente überlappen und in den gemeinsamen Bereich geklickt wird
- **THEN** erhält das obere das Ereignis
#### Scenario: Klick ohne Steuerelement
- **WHEN** auf eine freie Stelle des Formulars geklickt wird
- **THEN** erhält das Formular das Ereignis
#### Scenario: Ziehen und Ablegen
- **WHEN** ein Element mit `DragMode = 1` auf ein anderes gezogen und dort losgelassen wird
- **THEN** läuft am Ziel `DragOver` mit dem Zustand Over und danach `DragDrop` mit der Quelle als Argument
### Requirement: Steuerelemente mit Listeninhalt
ListBox und ComboBox SHALL `ADDITEM` und `REMOVEITEM` unterstützen und
`List`, `ListCount`, `ListIndex` und `Text` konsistent führen; bei
`Sorted = -1` SHALL die Einfügereihenfolge der Sortierung folgen.
`ListIndex = -1` SHALL „keine Auswahl" bedeuten. Die ComboBox SHALL die
drei Stilarten (Dropdown, Simple, Dropdown List) darstellen.
#### Scenario: Element hinzufügen
- **WHEN** `List1.ADDITEM "b"` und `List1.ADDITEM "a"` bei `Sorted = -1` ausgeführt werden
- **THEN** liefert `List1.List(0)` den Wert `a` und `List1.ListCount` den Wert 2
#### Scenario: Keine Auswahl
- **WHEN** eine ListBox ohne Auswahl gelesen wird
- **THEN** liefert `ListIndex` den Wert 1
### Requirement: Timer-Steuerelement
Ein Timer SHALL bei `Enabled = -1` und `Interval > 0` sein
`Timer`-Ereignis im eingestellten Abstand auslösen, gestützt auf die
Zeitquelle der Ereignissteuerung. `Interval = 0` SHALL ihn abschalten.
Sind mehrere Timer gleichzeitig fällig, SHALL die Reihenfolge festgelegt
und dokumentiert sein.
#### Scenario: Timer feuert im Abstand
- **WHEN** ein Timer mit `Interval = 100` läuft und die Zeit um 250 ms vorrückt
- **THEN** ist sein Ereignis zweimal gelaufen
#### Scenario: Interval 0 schaltet ab
- **WHEN** `Timer1.Interval = 0` gesetzt wird
- **THEN** läuft kein weiteres Ereignis
### Requirement: Menüsystem
Ein Formular SHALL eine Menüleiste mit bis zu sechs Ebenen tragen.
Menüeinträge SHALL Access-Keys (`&`), Shortcuts, `Checked`, `Enabled`,
`Visible` und Separatoren (`-`) unterstützen; ein Separator MUST NOT
`Checked`, deaktiviert oder mit Shortcut versehen sein, ein Menütitel
MUST NOT einen Shortcut tragen. Solange ein Menü geöffnet ist, MUST die
Zustellung von Zeitereignissen und klassischen Traps ruhen und danach
fortgesetzt werden.
#### Scenario: Menüauswahl löst Click aus
- **WHEN** ein Menüeintrag über seinen Access-Key gewählt wird
- **THEN** läuft seine `Click`-Prozedur
#### Scenario: Traps ruhen im geöffneten Menü
- **WHEN** ein Menü geöffnet ist und ein Zeit-Trap fällig wird
- **THEN** läuft sein Handler erst, nachdem das Menü geschlossen wurde
### Requirement: Vordefinierte Dialoge
`MSGBOX text$ [, typ% [, titel$]]` SHALL als Anweisung und als Funktion
verfügbar sein; die Funktion SHALL die gedrückte Schaltfläche als
INTEGER liefern (1 OK, 2 Cancel/Esc, 3 Abort, 4 Retry, 5 Ignore, 6 Yes,
7 No). `typ%` SHALL die Schaltflächengruppe (05) und die
Vorgabeschaltfläche (0/256/512) tragen. `INPUTBOX$(text$ [, titel$
[, vorgabe$ [, x%, y%]]])` SHALL eine Zeichenkette liefern und bei
Abbruch den leeren String. Beide Dialoge SHALL modal sein; `INPUTBOX$`
SHALL 46×16 Zeichen messen und ohne Positionsangabe zentriert
erscheinen.
#### Scenario: MSGBOX als Funktion
- **WHEN** `a% = MSGBOX("Weiter?", 4, "Frage")` ausgeführt und `Yes` gewählt wird
- **THEN** liefert der Aufruf 6
#### Scenario: INPUTBOX$ abgebrochen
- **WHEN** ein `INPUTBOX$`-Dialog mit Esc geschlossen wird
- **THEN** liefert er den leeren String
#### Scenario: Dialog ist modal
- **WHEN** ein Dialog offen ist
- **THEN** wird die Anweisung nach dem Aufruf erst nach dem Schließen ausgeführt

View File

@@ -128,3 +128,30 @@ Harness den Lauf abweisen statt auf die Systemuhr auszuweichen.
#### Scenario: Fehlende Zeitdeklaration
- **WHEN** ein Korpusprogramm zeitgesteuerte Traps nutzt, aber keinen Zeitverlauf deklariert
- **THEN** schlägt der Harness mit einer Meldung fehl, die die fehlende Deklaration nennt
### Requirement: Korpusabdeckung der Formularprogramme
Der Testkorpus SHALL Formularprogramme mit byte-genauer
Bildschirm-Sollausgabe führen. Ihre Ereignisfolge (Tasten, Maus, Zeit)
SHALL im Programmkopf deklariert und vom Harness eingespeist werden,
sodass ein Lauf ohne Terminal und ohne Wartezeit auskommt und zweimal
dasselbe Ergebnis liefert. Abgedeckt SHALL sein: Fokus- und
Tabreihenfolge, Access-Key, Klick über die Maus, Menüauswahl, ein
Listen-Steuerelement, ein Timer und ein modaler Dialog.
#### Scenario: Formularprogramm im Korpus
- **WHEN** ein Formular-Korpusprogramm mit deklarierter Ereignisfolge ausgeführt wird
- **THEN** entspricht der Bildschirminhalt byte-genau der Sollausgabe
#### Scenario: Wiederholbarkeit
- **WHEN** dasselbe Programm zweimal ausgeführt wird
- **THEN** ist die Ausgabe beide Male identisch
### Requirement: Kompatibilitätsnachweis an Fremdprogrammen
Die Formularprogramme aus dem öffentlichen Bestand des Vorbilds SHALL
sich ohne Diagnosen oder Non-Features übersetzen lassen und bedienbar
sein. Jeder entdeckte fehlende Sprach-, Projekt-, Formular- oder
Laufzeitpfad MUST implementiert und als Befund festgehalten werden.
#### Scenario: Fremdprogramm übersetzt
- **WHEN** ein Formularprogramm des öffentlichen Bestands übersetzt wird
- **THEN** entstehen keine Diagnosen und das Programm ist bedienbar