# forms-objektmodell Specification ## Purpose Das Forms-Objektmodell macht Formulare und Steuerelemente zu benannten Objekten des laufenden Programms: Eigenschaften lesen und schreiben, Formulare laden, zeigen, verbergen und entladen — modal wie nicht-modal —, Steuerelement-Arrays führen und Ereignisse an die Prozeduren `Name_Ereignis` zustellen. Es ist die Grundlage der Steuerelemente und der vordefinierten Dialoge. ## Requirements ### Requirement: Formulare und Steuerelemente als benannte Objekte Ein Formular SHALL unter seinem Namen ansprechbar sein, ein Steuerelement unter seinem Namen innerhalb seines Formulars. Eigenschaften SHALL über `objekt.eigenschaft` gelesen und geschrieben werden, mit dem in der Forms-Referenz festgelegten Typ und Wertebereich. Es SHALL keine Standardeigenschaft geben: `Text1 = "x"` MUST abgewiesen werden. Das Schreiben eines Wertes außerhalb des Wertebereichs MUST Laufzeitfehler 5 auslösen; eine zur Laufzeit schreibgeschützte Eigenschaft MUST bei Zuweisung einen Fehler auslösen. #### Scenario: Eigenschaft lesen und schreiben - **WHEN** `Text1.Text = "hallo"` ausgeführt und danach `Text1.Text` gelesen wird - **THEN** liefert der Zugriff `hallo` #### Scenario: Keine Standardeigenschaft - **WHEN** ein Programm `Text1 = "x"` enthält - **THEN** wird es abgewiesen und die Meldung nennt `Text1` #### Scenario: Wert außerhalb des Bereichs - **WHEN** `Check1.Value = 3` ausgeführt wird - **THEN** tritt Laufzeitfehler 5 auf #### Scenario: Getrennte Werte gleichnamiger Controls - **WHEN** Form1!Text1.Text auf a und Form2!Text1.Text auf b gesetzt werden - **THEN** liefern die beiden Zugriffe unabhängig a und b ### Requirement: Container-Zugriff über den Bang-Operator `form!steuerelement.eigenschaft` SHALL ein Steuerelement eines benannten Formulars ansprechen. Die Schreibweise MUST NOT mit dem Typsuffix `!` für SINGLE verwechselt werden; eine Variable `Form1!` und ein Zugriff `Form1!Text1` MUST unterscheidbar bleiben. #### Scenario: Zugriff über den Container - **WHEN** `Form1!Text1.Text = "a"` ausgeführt wird - **THEN** trägt die Eigenschaft `Text` des Steuerelements `Text1` in `Form1` den Wert `a` #### Scenario: Typsuffix bleibt Typsuffix - **WHEN** ein Programm die Variable `Wert!` verwendet - **THEN** bleibt sie eine SINGLE-Variable und wird nicht als Containerzugriff gelesen ### Requirement: Lade- und Entladezyklus `LOAD form` SHALL das Formular anlegen und `Form_Load` ausführen, bevor es sichtbar wird. `UNLOAD form` SHALL `Form_Unload (Cancel)` ausführen; ein von der Prozedur gesetzter Wert `Cancel <> 0` MUST das Entladen verhindern. `HIDE` SHALL nur die Sichtbarkeit zurücknehmen und das Formular geladen lassen. Der Zugriff auf ein nicht geladenes Formular SHALL es implizit laden. #### Scenario: Load läuft vor der Anzeige - **WHEN** ein Formular gezeigt wird, dessen `Form_Load` eine Eigenschaft setzt - **THEN** ist der gesetzte Wert bereits in der ersten Anzeige sichtbar #### Scenario: Entladen abbrechen - **WHEN** `Form_Unload` den Parameter `Cancel` auf 1 setzt und `UNLOAD Form1` ausgeführt wird - **THEN** bleibt das Formular geladen und sichtbar #### Scenario: HIDE entlädt nicht - **WHEN** `Form1.HIDE` ausgeführt und danach eine Eigenschaft von `Form1` gelesen wird - **THEN** ist der zuvor gesetzte Wert erhalten und `Form_Load` läuft nicht erneut ### Requirement: Modales und nicht-modales Anzeigen `form.SHOW [style%]` SHALL das Formular anzeigen; `style%` 0 (Vorgabe) zeigt es nicht-modal, 1 modal. Bei modaler Anzeige MUST die Anweisung nach `SHOW` erst ausgeführt werden, wenn das Formular entladen oder verborgen wurde; die Ereignisschleife MUST währenddessen weiterlaufen. Verstöße gegen die Stapelregeln des Vorbilds MUST die Fehler 400–403 auslösen. #### Scenario: Modal hält den Ablauf an - **WHEN** ein Programm `Form1.SHOW 1 : PRINT "danach"` ausführt und ein Ereignis `Form1` entlädt - **THEN** erscheint `danach` erst nach dem Entladen #### Scenario: Ereignisse laufen während der Modalität - **WHEN** ein modales Formular angezeigt wird und ein Ereignis eintrifft - **THEN** läuft die zugehörige Ereignisprozedur ### Requirement: Steuerelement-Arrays Steuerelemente mit gleichem Namen und `Index` SHALL als Array ansprechbar sein. `LOAD ctl(index%)` SHALL ein weiteres Element zur Laufzeit anlegen, `UNLOAD ctl(index%)` es entfernen. Der Versuch, ein zur Entwurfszeit angelegtes Element zu entladen, MUST Fehler 362 auslösen. Bei einem Array MUST `Index AS INTEGER` als erster Parameter der Ereignisprozedur übergeben werden. #### Scenario: Element zur Laufzeit anlegen - **WHEN** `LOAD Command1(3)` ausgeführt wird - **THEN** existiert `Command1(3)` mit den Eigenschaften des Elements 0 als Vorlage #### Scenario: Entwurfszeit-Element ist nicht entladbar - **WHEN** `UNLOAD Command1(0)` für ein zur Entwurfszeit angelegtes Element ausgeführt wird - **THEN** tritt Fehler 362 auf #### Scenario: Index als erster Parameter - **WHEN** ein Klick auf `Command1(3)` zugestellt wird - **THEN** wird `Command1_Click` mit `Index = 3` aufgerufen ### Requirement: Ereignisdispatch an Name_Ereignis Ein Ereignis SHALL die Prozedur `Name_Ereignis` des betroffenen Objekts aufrufen und ihr die Argumente der in der Forms-Referenz festgelegten Signatur übergeben. Fehlt die Prozedur, MUST das Ereignis wirkungslos verfallen, ohne Fehler. Die Zustellung SHALL an den Zustellpunkten der Ereignissteuerung erfolgen; es MUST NOT neue Zustellpunkte geben. #### Scenario: Ereignisprozedur wird gerufen - **WHEN** ein Klick auf `Command1` zugestellt wird und `SUB Command1_Click` existiert - **THEN** läuft die Prozedur genau einmal #### Scenario: Fehlende Ereignisprozedur - **WHEN** ein Klick auf ein Steuerelement ohne passende Prozedur zugestellt wird - **THEN** läuft das Programm unverändert weiter und es entsteht kein Fehler #### Scenario: Signatur mit Mausargumenten - **WHEN** `Form_MouseDown` definiert ist und ein Mausereignis in Zeile 5, Spalte 7 zugestellt wird - **THEN** erhält die Prozedur Taste, Umschaltzustand und die Position in Zellen ### Requirement: SCREEN-Objekt `SCREEN` SHALL als Objekt ansprechbar sein mit `ActiveControl`, `ActiveForm`, `Height`, `Width`, `MousePointer` und `ControlPanel` sowie den Methoden `SHOW` und `HIDE`. `Height` und `Width` SHALL die **aktuelle** Terminalgröße in Zeichen liefern und schreibgeschützt sein; die feste Größe des Vorbilds MUST als Abweichung dokumentiert sein. #### Scenario: Größe folgt dem Terminal - **WHEN** die Darstellungsfläche 120×40 misst und `SCREEN.Width` gelesen wird - **THEN** liefert es 120 #### Scenario: Aktives Formular - **WHEN** zwei Formulare geladen sind und eines den Fokus hat - **THEN** liefert `SCREEN.ActiveForm` dieses Formular