====== 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.