====== std.lfd_factory ======
Vorgesehene Widget-Factory für LFD-Formulare: Sie soll den von [[lyx_-_programmiersprache:units:lfd_parser|std.lfd_parser]] gelieferten Syntaxbaum in echte Bedienelemente übersetzen (laut Quellkommentar über ''libqtlyx.so'').
→ [[lyx_-_programmiersprache:units:lfd_parser|std.lfd_parser]] · [[lyx_-_programmiersprache:units|Standard Library]] · [[lyx_-_programmiersprache:units:qt5_core|std.qt5_core]]
Alle Beispiele dieser Seite sind mit ''lyxc 1.0.21A'' übersetzt und ausgeführt; die gezeigten Ausgaben sind echte Programmausgaben.
> **Diese Unit ist eine leere Hülle — sie erzeugt keine Widgets.** Jede Funktion übersetzt, keine tut etwas: ''createWidget'' und ''createLayout'' geben unter allen Umständen ''0'' zurück, ''renderForm'' ebenso, und die Setter melden ''false'', weil ihre erste Prüfung (''wid == 0'') immer zutrifft. Es gibt keine ''extern fn''-Deklaration und keine ''link''-Klausel; ''libqtlyx.so'' wird nirgends gebunden.
>
> Zweiter Befund: Die Fallunterscheidungen im Quelltext (''%%if (widgetType == "Button")%%'') vergleichen bei ''pchar'' die **Adressen**, nicht den Inhalt — sie träfen also selbst dann nicht zu, wenn darunter etwas läge. Für Textvergleiche ist ''StrEquals'' zuständig.
>
> Wer heute ein LFD-Formular anzeigen will, geht den Weg unten: mit ''std.lfd_parser'' parsen und den Baum selbst durchlaufen.
----
===== Der belegte Stand =====
import std.lfd_factory;
import std.string;
fn main(): int64 {
var w: int64 := createWidget("Button"c, 0);
PrintLn(StrConcat("createWidget(Button): ", IntToStr(w)));
PrintLn(StrConcat("setWidgetProperty: ", IntToStr(setWidgetProperty(w, "Text"c, "OK"c) as int64)));
var l: int64 := createLayout("Vertical"c);
PrintLn(StrConcat("createLayout(Vertical): ", IntToStr(l)));
PrintLn(StrConcat("addWidgetToLayout: ", IntToStr(addWidgetToLayout(l, w) as int64)));
return 0;
}
createWidget(Button): 0
setWidgetProperty: 0
createLayout(Vertical): 0
addWidgetToLayout: 0
Zum Adressvergleich, der die Verzweigungen der Unit wirkungslos macht:
import std.string;
fn main(): int64 {
var a: pchar := "Button"c;
var b: pchar := "Button"c;
PrintLn(StrConcat("a == b (Adressvergleich): ", IntToStr((a == b) as int64)));
PrintLn(StrConcat("StrEquals(a, b): ", IntToStr(StrEquals(a, b))));
return 0;
}
a == b (Adressvergleich): 0
StrEquals(a, b): 1
----
===== Was die Schnittstelle vorsieht =====
Die Signaturen beschreiben ein vollständiges Modell — sie sind der Bauplan, nach dem eine spätere Umsetzung arbeiten müsste.
^ Signatur ^ Vorgesehene Aufgabe ^ Heutiger Rückgabewert ^
| ''createWidget(widgetType: pchar, parent: int64): int64'' | Bedienelement des genannten Typs unter ''parent'' anlegen | immer ''0'' |
| ''setWidgetProperty(wid, propertyName: pchar, value: pchar): bool'' | Texteigenschaft setzen | immer ''false'' |
| ''setWidgetIntProperty(wid, propertyName: pchar, value: int64): bool'' | Zahleneigenschaft setzen | immer ''false'' |
| ''createLayout(layoutType: pchar): int64'' | Anordnung anlegen | immer ''0'' |
| ''addWidgetToLayout(lay: int64, wid: int64): bool'' | Element in eine Anordnung hängen | immer ''false'' |
| ''setLayoutOnWidget(wid: int64, lay: int64): bool'' | Anordnung an einem Element setzen | immer ''false'' |
| ''bindEvent(wid, eventName: pchar, handler: pchar): bool'' | Ereignisbehandler verbinden | immer ''false'' |
| ''renderForm(parser: int64): int64'' | Fertigen Syntaxbaum in ein Fenster übersetzen | immer ''0'' |
| ''parseAndRender(lfdSource: pchar): int64'' | Quelltext parsen und anzeigen | immer ''0'' |
Die im Quelltext aufgezählten Werte — sie zeigen, welchen Umfang die Factory abdecken soll:
^ Kategorie ^ Vorgesehene Werte ^
| Widget-Typen | ''Button'', ''Label'', ''Input'', ''Checkbox'', ''RadioButton'', ''ComboBox'', ''SpinBox'', ''Slider'' |
| Texteigenschaften | ''Text'', ''Enabled'', ''Visible'', ''ToolTip'', ''Placeholder'' |
| Zahleneigenschaften | ''Width'', ''Height'', ''Value'', ''Min'', ''Max'' |
| Anordnungen | ''Vertical'', ''Horizontal'', ''Grid'' |
| Ereignisse | ''OnClick'', ''OnChange'' |
''parseAndRender'' ist die einzige Funktion mit echtem Inhalt: Sie ruft ''LFDParserNew'' und ''LFDValidate'' aus ''std.lfd_parser'' und gibt bei einem Fehler die Meldung aus — danach landet sie in ''renderForm'' und damit bei ''0''.
> **Der Parser dagegen arbeitet.** ''std.lfd_parser'' hat einen vollständigen Lexer und baut einen begehbaren Syntaxbaum. Alles, was auf dieser Seite fehlt, betrifft **nur** den Schritt vom Baum zum sichtbaren Fenster.
----
===== Der Weg, der heute funktioniert =====
Statt ''renderForm'' schreibt man den Durchlauf selbst. Der Baum ist klein: Knotentyp abfragen, Kinder zählen, absteigen. Was am Ende erzeugt wird — Qt-Fenster, Terminaloberfläche oder wie hier eine Textbeschreibung — entscheidet die eigene Funktion.
import std.lfd_parser;
import std.string;
// Eigener Renderer: statt Qt-Widgets erzeugt er eine Textbeschreibung.
// Genau diese Rolle hätte std.lfd_factory - solange sie leer ist, schreibt
// man den Durchlauf selbst.
fn Einzug(t: int64): pchar {
var s: pchar := "";
var i: int64 := 0;
while (i < t) { s := StrConcat(s, " "); i := i + 1; }
return s;
}
fn Rendere(node: int64, tiefe: int64): void {
var typ: int64 := LFDGetNodeType(node);
var kinder: int64 := LFDGetNodeChildCount(node);
if (typ == LFD_TK_FORM) { PrintLn(StrConcat(Einzug(tiefe), "Fenster")); }
if (typ == LFD_TK_VERTICAL) { PrintLn(StrConcat(Einzug(tiefe), "senkrechte Box")); }
if (typ == LFD_TK_HORIZONTAL) { PrintLn(StrConcat(Einzug(tiefe), "waagerechte Box")); }
if (typ == LFD_TK_LABEL) { PrintLn(StrConcat(Einzug(tiefe), "Beschriftung")); }
if (typ == LFD_TK_INPUT) { PrintLn(StrConcat(Einzug(tiefe), "Eingabefeld")); }
if (typ == LFD_TK_BUTTON) { PrintLn(StrConcat(Einzug(tiefe), "Schaltflaeche")); }
if (typ == LFD_NODE_PROPERTY) {
PrintLn(StrConcat(StrConcat(Einzug(tiefe), "Eigenschaft = "), IntToStr(LFDGetNodeIntVal(node))));
}
var i: int64 := 0;
while (i < kinder) { Rendere(LFDGetNodeChild(node, i), tiefe + 1); i := i + 1; }
}
fn main(): int64 {
var quelle: pchar := "form { vertical { label \"Benutzer\" { } input \"\" { width: 200 } button \"Anmelden\" { width: 100 height: 30 } } }"c;
var root: int64 := LFDParseString(quelle);
if (root < 0) { PrintLn("Parse-Fehler"); return 1; }
Rendere(root, 0);
return 0;
}
Fenster
senkrechte Box
Beschriftung
Eingabefeld
Eigenschaft = 200
Schaltflaeche
Eigenschaft = 100
Eigenschaft = 30
> **Die tatsächlich geparste Syntax ist klein geschrieben und kennt keine Namen.** Der Entwurf in ''lfd-ebnf.md'' beschreibt ''%%Form Anmeldung "Login" { Layout Vertical { … } }%%'' — der Parser erwartet dagegen ''%%form { vertical { button "OK" { width: 100 } } }%%''. Großgeschriebene Schlüsselwörter und Bezeichner zwischen Typ und Titel führen zu ''-1''. Wer sich an der Grammatikdatei orientiert, bekommt Parse-Fehler; maßgeblich ist heute der Parser.
Die Zuordnung Knotentyp → Bedeutung steht in ''std.lfd_parser'': ''LFD_TK_FORM'' (0), ''LFD_TK_VERTICAL'' (2), ''LFD_TK_BUTTON'' (6), ''LFD_TK_LABEL'' (7), ''LFD_TK_INPUT'' (8) und so fort; Eigenschaftsknoten tragen ''LFD_NODE_PROPERTY'' (101), ihren Zahlwert liefert ''LFDGetNodeIntVal''.
----
===== Wenn ein echtes Fenster gebraucht wird =====
^ Weg ^ Wofür ^
| [[lyx_-_programmiersprache:units:qt5:app|std.qt5.app]] / [[lyx_-_programmiersprache:units:qt5_core|std.qt5_core]] | Qt-Oberflächen direkt aus Lyx — der Weg, den die Factory eines Tages abkürzen soll |
| [[lyx_-_programmiersprache:units:tui|std.tui]] | Terminaloberflächen ohne Grafiksystem |
| eigener Durchlauf über ''std.lfd_parser'' | Formularbeschreibung in beliebige Ziele übersetzen — auch in HTML, JSON oder eine Prüfausgabe |
Der Umweg über den Parser hat einen Vorteil: Die Formularbeschreibung bleibt frei von Zielsystem-Details, und derselbe Baum lässt sich für Tests in Text ausgeben und im Betrieb in Widgets übersetzen.
----
===== Offene Punkte =====
* Keine Bindung an ''libqtlyx.so'' — es fehlt die ''extern fn''-Deklaration samt ''link''-Klausel (Pflicht seit lyxc 1.0.17C, #1179).
* Die Fallunterscheidungen müssen von ''=='' auf ''StrEquals'' umgestellt werden, sonst greifen sie auch nach einer Umsetzung nicht.
* ''renderForm'' bekommt einen ''parser''-Zeiger, benutzt ihn aber nicht; ein echter Durchlauf müsste ''LFDGetNodeChild''/''LFDGetNodeType'' verwenden — wie im Beispiel oben.
* Die Widget-Liste der Factory (8 Typen) ist kleiner als die des Parsers (17 Typen, bis ''TabWidget'', ''Splitter'', ''WebView''); die Grammatikdatei nennt noch mehr.
* ''@description'' der Unit lautet „LFD binary file writer" — das beschreibt eine andere Aufgabe als der Code (Widget-Factory).
----
**Weiterführend:** [[lyx_-_programmiersprache:units:lfd_parser|std.lfd_parser — Lexer, Syntaxbaum, Fehlerbehandlung]] · [[lyx_-_programmiersprache:units|Standard Library]]
**Quelle:** ''std/lfd_factory.lyx'' (82 Zeilen) · **Autor:** Andreas Röne · **Copyright:** 2024–2025 Andreas Röne
Letzte Aktualisierung: 2026-08-13 — Seite gegen ''std/lfd_factory.lyx'' neu geschrieben. Die alte Einleitung beschrieb einen „LFD-Binärformat-Erzeuger, der typisierte Felder serialisiert" — die Unit ist eine Widget-Factory, und zwar eine leere: alle Rückgabewerte sind ''0'' bzw. ''false'', nachgemessen mit lyxc 1.0.21A. Ergänzt: Beleg dazu, der Adressvergleich-Befund bei ''pchar'', die vorgesehenen Typ-/Eigenschafts-/Ereignislisten, ein lauffähiger eigener Renderer über ''std.lfd_parser'', die Abweichung zwischen ''lfd-ebnf.md'' und der geparsten Syntax sowie die offenen Punkte für eine Umsetzung.