# 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 ``, 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 `` #### 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. Die über das Terminal gelieferte Rückwärtstab-Taste SHALL denselben Fokuswechsel wie Tab mit Umschalt auslösen. Die Reihenfolge LostFocus vor GotFocus SHALL auch an den Wirkungen der BASIC-Handler sichtbar bleiben. #### 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` #### Scenario: Handlerwirkungen in Fokusreihenfolge - **WHEN** LostFocus den Text L und GotFocus den Text G an dieselbe Variable anhängen - **THEN** lautet das Ergebnis LG #### Scenario: Rückwärtstab vom Terminal - **WHEN** das Terminal eine Rückwärtstab-Taste liefert - **THEN** wechselt der Fokus zum vorherigen zulässigen TabIndex ### 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. Eine Zuweisung von ListIndex = -1 SHALL in leerer wie gefüllter Liste zulässig sein. Einfügen vor der Auswahl SHALL ihren Index verschieben, Entfernen der Auswahl SHALL sie aufheben. Eine ListBox ohne Auswahl SHALL Text als leeren String liefern; editierbare ComboBox-Stile SHALL ihren unabhängigen Eingabetext erhalten. #### 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 #### Scenario: Auswahl ausdrücklich aufheben - **WHEN** nach ADDITEM die Eigenschaft ListIndex auf -1 gesetzt wird - **THEN** tritt kein Fehler auf und ListIndex ist -1 #### Scenario: Eintrag vor Auswahl einfügen - **WHEN** vor einem ausgewählten Eintrag ein Element eingefügt wird - **THEN** bleibt derselbe Eintrag ausgewählt und sein Index steigt um 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. Die erste Frist SHALL ab dem Einschalten beziehungsweise neu gesetzten Intervall zählen. Zeit vor der Aktivierung MUST NOT nachgeholt werden. Deaktivierung oder Interval = 0 SHALL noch anstehende Timerereignisse verwerfen. #### 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 #### Scenario: Späte Aktivierung - **WHEN** bei Hostzeit 1000 ms ein zuvor inaktiver Timer mit Interval 100 eingeschaltet wird - **THEN** läuft bis 1099 ms kein Timerereignis und bei 1100 ms genau eines #### Scenario: Abschalten verwirft anstehende Ereignisse - **WHEN** Timerereignisse anstehen und vor ihrer Zustellung Interval auf 0 gesetzt wird - **THEN** werden sie nicht mehr zugestellt ### 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 #### Scenario: UEVENT an gewöhnlicher Anweisungsgrenze - **WHEN** ein Menü offen ist und UEVENT vor einer Zuweisung ansteht - **THEN** läuft dessen Handler erst nach dem Schließen des Menüs ### 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 (0–5) 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