;; ============================================================ ;; GeruestInsert.lsp - Geruest-Baugruppen konfigurieren und einfuegen ;; ;; Liest data/json/geruest.json (rekursiv per ssg-json-laden), laesst den ;; Nutzer eine Basis-Variante, Anbauteile fuer "Befestigung oben" UND ;; "Befestigung unten" (je mit eigener Stueckzahl), Laenge und Farbe waehlen, ;; und fuegt das Ergebnis als Block GR__ ein. ;; ;; Beide Befestigungslisten enthalten ALLE Anbauteile der Baugruppe - dasselbe ;; Teil kann oben, unten oder gleichzeitig an beiden Positionen sitzen. ;; ;; Die Dialogdefinition wird zur Laufzeit erzeugt (geruest-dcl-schreiben): ;; eine DCL-Liste kann keine Eingabefelder enthalten, ein Mengenfeld je Teil ;; ist also nur mit generierten Zeilen moeglich. ;; ;; Konfigurationen kommen aus zwei getrennten Quellen: der gepflegten ;; Bibliothek in geruest.json und den eigenen in cfg/geruest_user.json. ;; ;; Der Block wird - wie KREISEL_n/VF_n - selbst zusammengebaut: die Dummy-DWG ;; aus data/geruest liefert nur die Geometrie, das Attribut-Schema kommt aus ;; *geruest-attrib-defs*. Damit kann kein Attribut still verlorengehen, wenn ;; die Dummy-DWG einen Tag nicht kennt (ssg-attrib-set-on schreibt nur Tags, ;; die als ATTDEF existieren). ;; ;; Das GR_-Praefix ist nicht kosmetisch: SSG_BLOCKEDIT haelt jeden Block mit ;; TEILEART-Attribut fuer ein Omniflo-Element (SSG_LIB_Commands.lsp). Der ;; Doppelklick-Dispatcher erkennt Geruest-Bloecke an diesem Praefix. ;; ;; Alle Bereiche liegen in EINEM Dialog; oben wird per Dropdown zwischen ;; Rohrabhaenger, Saeulen und Wandbefestigung umgeschaltet. DCL hat kein ;; Reiter-Tile, und da sich die Teilezeilen je Bereich unterscheiden, wird der ;; Dialog beim Wechsel geschlossen und neu aufgebaut - der Stand jedes ;; Bereichs bleibt dabei in *geruest-zustand* erhalten. ;; ;; Befehl: GERUEST ;; ============================================================ (vl-load-com) ;; Attribut-Schema des Wrapper-Blocks. Die Dummy-DWG darf eigene Tags ;; mitbringen - die bleiben erhalten (ssg-attrib-merge). ;; "ID" (leer vorbelegt, wie bei Kreisel/VF_n/GF_n) ist Voraussetzung dafuer, ;; dass ssg-id-check-all dem Block ueberhaupt eine ID zuweisen kann - ;; ssg-attrib-set-on schreibt nur auf ein bereits vorhandenes ATTDEF, siehe ;; oben. Ohne diesen Eintrag bliebe ID fuer immer leer (csv:read-attribs ;; exportiert dann eben kein "ID"-Feld statt eines Werts). (if (null *geruest-attrib-defs*) (setq *geruest-attrib-defs* '(("ID" "") ("ARTINR" "") ("LAENGE" "") ("BEZEICHNUNG" "") ("TEILEART" "") ("TEILEFARBE" "") ("LAYER" "") ) ) ) (if (null *geruest-block-counter*) (setq *geruest-block-counter* 0)) ;; ============================================================ ;; DATEN ;; ============================================================ (defun geruest-data-verzeichnis ( / ) (cond ((getenv "DXFM_DATA") (vl-string-translate "\\" "/" (getenv "DXFM_DATA"))) ((getenv "DXFMAKRO") (strcat (vl-string-translate "\\" "/" (getenv "DXFMAKRO")) "/data")) ) ) (defun geruest-json-pfad ( / basis) (if (setq basis (geruest-data-verzeichnis)) (strcat basis "/json/geruest.json") ) ) (defun geruest-dummy-pfad (datei / basis) (if (and datei (setq basis (geruest-data-verzeichnis))) (strcat basis "/geruest/" datei) ) ) ;; Datendatei einmal je Zeichnungssitzung laden. (defun geruest-daten ( / pfad) (if (null *geruest-daten*) (progn (setq pfad (geruest-json-pfad)) (cond ((null pfad) (princ (ssg-text "gr-fehler-datenpfad"))) ((null (findfile pfad)) (princ (ssg-textf "gr-fehler-json-fehlt" (list pfad)))) (T (setq *geruest-daten* (ssg-json-laden pfad)) (if (null *geruest-daten*) (princ (ssg-textf "gr-fehler-json-lesbar" (list pfad))) ) ) ) ) ) *geruest-daten* ) ;; Alle Baugruppen als ((id . objekt) ...) in Dateireihenfolge - diese ;; Reihenfolge bestimmt auch die Reihenfolge im Bereichs-Dropdown. (defun geruest-baugruppen-liste ( / erg) (setq erg nil) (foreach eintrag (geruest-daten) (if (listp (cdr eintrag)) (setq erg (append erg (list (cons (ssg-json-get (cdr eintrag) "id") (cdr eintrag))))) ) ) erg ) ;; Anzeigename einer Baugruppe fuer Dropdown und Kopfzeile. Bewusst das ;; ASCII-Feld "titel" und nicht der aeussere JSON-Schluessel - der traegt ;; Umlaute ("Rohrabhänger", "Säulen"). (defun geruest-titel (bg / t1) (setq t1 (ssg-json-get bg "titel")) (if (and t1 (= (type t1) 'STR) (/= t1 "")) t1 (ssg-json-get bg "teileart") ) ) ;; Wert einer Variante mit Rueckfall auf die Baugruppe. Genutzt fuer ;; "teileart" (die Saeulen-Varianten unterscheiden 1 Zoll von 2 Zoll, was im ;; Export sichtbar bleiben muss) und "dummy" (eine Variante darf eine eigene ;; DWG mitbringen, sobald es sie gibt). (defun geruest-variante-wert (variante bg schluessel / w) (setq w (if variante (ssg-json-get variante schluessel))) (if (and w (/= w "")) w (ssg-json-get bg schluessel)) ) ;; ============================================================ ;; TEILE AUSWERTEN ;; ============================================================ ;; Anzeigename eines Eintrags: benannte Gruppe ("name") oder Einzelteil ;; ("artikel"). (defun geruest-eintrag-name (eintrag / n) (setq n (ssg-json-get eintrag "name")) (if (and n (= (type n) 'STR) (/= n "")) n (ssg-json-get eintrag "artikel") ) ) (defun geruest-menge (eintrag / m) (setq m (ssg-json-get eintrag "menge")) (if (and m (numberp m) (> m 0)) (fix m) 1) ) ;; Sivas-ID als String. Im JSON stehen rein numerische IDs als Zahl ;; (Projektkonvention), zusammengesetzte Codes waeren Strings. (defun geruest-id-string (wert) (cond ((null wert) nil) ((= (type wert) 'STR) wert) ((= (type wert) 'INT) (itoa wert)) ((= (type wert) 'REAL) (rtos wert 2 0)) ) ) (defun geruest-wiederholen (wert n / erg i) (setq erg nil i 0) (if wert (while (< i n) (setq erg (cons wert erg)) (setq i (1+ i)) ) ) erg ) ;; Alle Artikelnummern eines Eintrags, jede gemaess "menge" wiederholt. ;; Benannte Gruppen ("teile") werden rekursiv aufgeloest. (defun geruest-artikelnummern (eintrag / erg teile) (setq erg nil) (setq teile (ssg-json-get eintrag "teile")) (if teile (foreach teil teile (setq erg (append erg (geruest-artikelnummern teil))) ) (setq erg (geruest-wiederholen (geruest-id-string (ssg-json-get eintrag "sivas_id")) (geruest-menge eintrag))) ) erg ) ;; ============================================================ ;; DIALOG ;; ============================================================ ;; Reine Ziffernfolge? atoi allein taugt als Pruefung nicht - "abc" liefert ;; dort still 0. (defun geruest-zahl-p (s / i c ok) (setq ok (> (strlen s) 0) i 1) (while (and ok (<= i (strlen s))) (setq c (ascii (substr s i 1))) (if (or (< c 48) (> c 57)) (setq ok nil)) (setq i (1+ i)) ) ok ) ;; Eingabe aus einem Mengenfeld auswerten. ;; Leer -> Vorgabewert aus dem JSON, gueltig -> Zahl >= 1, sonst nil. (defun geruest-menge-wert (s vorgabe) (setq s (ssg-cfg-trim (if s s ""))) (cond ((= s "") vorgabe) ((not (geruest-zahl-p s)) nil) ((< (atoi s) 1) nil) (T (atoi s)) ) ) ;; Zahl aus dem JSON als Anzeigetext (fehlender Wert -> ""). (defun geruest-zahl-string (w) (cond ((null w) "") ((= (type w) 'STR) w) ((= (type w) 'INT) (itoa w)) ((= (type w) 'REAL) (rtos w 2 0)) (T "") ) ) ;; Artikelnummern eines Eintrags bei frei gewaehlter Stueckzahl. ;; Einzelteil: die Sivas-ID anzahl-mal. Benannte Gruppe ("teile"): das ;; komplette Set anzahl-mal - die Mengen INNERHALB des Sets bleiben erhalten ;; (ein Schraubenset bleibt 1 Scheibe + 2 Muttern + 1 Schraube je Satz). (defun geruest-artikelnummern-n (eintrag anzahl / teile einmal erg i) (setq teile (ssg-json-get eintrag "teile")) (if teile (progn (setq einmal nil) (foreach teil teile (setq einmal (append einmal (geruest-artikelnummern teil))) ) (setq erg nil i 0) (while (< i anzahl) (setq erg (append erg einmal)) (setq i (1+ i)) ) erg ) (geruest-wiederholen (geruest-id-string (ssg-json-get eintrag "sivas_id")) anzahl) ) ) ;; Index eines Eintrags (Variante oder Anbauteil) ueber seinen Anzeigenamen. (defun geruest-name-index (name liste / i idx) (setq i 0 idx nil) (foreach e liste (if (and (null idx) (equal (geruest-eintrag-name e) name)) (setq idx i)) (setq i (1+ i)) ) idx ) ;; Schluessel in einer Alist setzen oder anhaengen. (defun geruest-alist-setzen (alist key wert) (if (assoc key alist) (subst (cons key wert) (assoc key alist) alist) (append alist (list (cons key wert))) ) ) ;; n-tes Element ersetzen - AutoLISP kann nth nicht schreibend nutzen. (defun geruest-liste-setzen (lst idx wert / erg i) (setq erg nil i 0) (foreach e lst (setq erg (cons (if (= i idx) wert e) erg)) (setq i (1+ i)) ) (reverse erg) ) (defun geruest-nil-liste (n / erg i) (setq erg nil i 0) (while (< i n) (setq erg (cons nil erg)) (setq i (1+ i))) erg ) ;; ============================================================ ;; KONFIGURATIONEN ;; ============================================================ ;; Zwei Quellen: die gepflegte Bibliothek in data/json/geruest.json ;; (schreibgeschuetzt) und die eigenen Zusammenstellungen in ;; cfg/geruest_user.json. Beide werden NICHT vermischt - Benutzerdaten in der ;; versionierten Datendatei wuerden bei jedem Git-Update kollidieren. (defun geruest-user-pfad ( / ) (cond ((getenv "DXFM_CFG") (strcat (vl-string-translate "\\" "/" (getenv "DXFM_CFG")) "/geruest_user.json")) ((getenv "DXFMAKRO") (strcat (vl-string-translate "\\" "/" (getenv "DXFMAKRO")) "/cfg/geruest_user.json")) ) ) ;; Benutzerdatei laden (Baugruppen-id -> Liste von Konfigurationen). ;; Eine fehlende Datei ist kein Fehler - sie entsteht beim ersten Speichern. (defun geruest-user-daten ( / pfad) (if (null *geruest-user-daten*) (progn (setq pfad (geruest-user-pfad)) (if (and pfad (findfile pfad)) (setq *geruest-user-daten* (ssg-json-laden pfad)) ) ) ) *geruest-user-daten* ) ;; Alle Konfigurationen einer Baugruppe, Bibliothek zuerst. ;; Eintrag: (benutzer-p . json-objekt) (defun geruest-konfigs (bg / erg) (setq erg nil) (foreach k (ssg-json-get bg "konfigurationen") (setq erg (append erg (list (cons nil k)))) ) (foreach k (ssg-json-get (geruest-user-daten) (ssg-json-get bg "id")) (setq erg (append erg (list (cons T k)))) ) erg ) ;; Anzeigename; eigene Eintraege mit * markiert, damit erkennbar ist, was ;; geloescht werden kann. (defun geruest-konfig-name (k) (strcat (if (car k) "* " "") (ssg-json-get (cdr k) "name")) ) ;; Listenindex einer Konfiguration im popup_list (0 = "", die ;; Konfigurationen beginnen deshalb bei 1). 0, wenn nicht gefunden. (defun geruest-konfig-index (name / i idx) (setq i 1 idx 0) (foreach k *geruest-konfig-liste* (if (and (= idx 0) (equal (ssg-json-get (cdr k) "name") name)) (setq idx i)) (setq i (1+ i)) ) idx ) ;; Positionsliste ("oben"/"unten") einer Konfiguration auf die Anbauteile ;; abbilden. Rueckgabe: ein Eintrag je Anbauteil - nil (nicht gewaehlt) oder ;; die Stueckzahl. Ein unbekannter Artikelname wird gemeldet und ;; uebersprungen, statt die ganze Konfiguration scheitern zu lassen. (defun geruest-konfig-position (konfig schluessel anbauteile / mengen idx n) (setq mengen (geruest-nil-liste (length anbauteile))) (foreach e (ssg-json-get konfig schluessel) (setq idx (geruest-name-index (ssg-json-get e "artikel") anbauteile)) (if idx (progn (setq n (ssg-json-get e "menge")) (setq mengen (geruest-liste-setzen mengen idx (if (and n (numberp n) (> n 0)) (fix n) 1))) ) (princ (ssg-textf "gr-konfig-teil-unbekannt" (list (ssg-json-get e "artikel") (ssg-json-get konfig "name")))) ) ) mengen ) ;; ============================================================ ;; DIALOGDEFINITION ERZEUGEN ;; ============================================================ ;; Die Anbauteil-Zeilen haengen an der Baugruppe, deshalb wird die DCL-Datei ;; pro Aufruf geschrieben statt fest vorgehalten: DCL kann weder Dateien ;; einbinden noch Tiles zur Laufzeit erzeugen, und eine Liste (list_box) kann ;; keine Eingabefelder enthalten - ohne Generierung gaebe es also kein ;; Mengenfeld je Teil. ;; Ein Anfuehrungszeichen im Artikelnamen wuerde das DCL-Label vorzeitig ;; beenden und die erzeugte Datei unbrauchbar machen (fuenf Bezeichnungen ;; enthalten eines, z.B. ROHRKLAMMER 1" KPL. VERTIKAL). Betrifft nur die ;; Anzeige - ARTINR und BEZEICHNUNG nutzen weiter den Originalnamen. (defun geruest-dcl-label (s / i c erg) (if (null s) (setq s "")) (setq erg "" i 1) (while (<= i (strlen s)) (setq c (substr s i 1)) (setq erg (strcat erg (if (= c "\"") "''" c))) (setq i (1+ i)) ) erg ) ;; Eine Befestigungsspalte. Das Mengenfeld steht LINKS vom Ankreuzfeld: die ;; Eingabefelder sind dadurch alle gleich breit und die Teilenamen beginnen ;; auf gleicher Hoehe - DCL richtet Zeileninhalte nicht von sich aus aus. ;; ;; Zwei DCL-Eigenheiten muessen dafuer gesetzt werden: ;; - alignment = left, weil DCL Tiles in einer Spalte sonst ZENTRIERT: bei ;; unterschiedlich langen Teilenamen wandern die Zeilen sonst verschieden ;; weit nach rechts und die Liste franst aus. ;; - fixed_width = true auf der Zeile, weil eine gestreckte row ihre Tiles ;; ueber die volle Breite VERTEILT - zwischen Mengenfeld und Ankreuzfeld ;; klaffte dadurch eine wechselnd grosse Luecke. Mit fixed_width wird die ;; Zeile nur so breit wie ihr Inhalt, das Ankreuzfeld sitzt also direkt am ;; Mengenfeld. (defun geruest-dcl-spalte (f anbauteile prefix titel / i) (write-line " : boxed_column {" f) (write-line (strcat " label = \"" titel "\";") f) (write-line " alignment = left;" f) (setq i 0) (foreach a anbauteile (write-line " : row {" f) (write-line " alignment = left;" f) (write-line " fixed_width = true;" f) (write-line (strcat " : edit_box { key = \"" prefix "m" (itoa i) "\"; label = \"\"; edit_width = 3;" " fixed_width = true; }") f) (write-line (strcat " : toggle { key = \"" prefix (itoa i) "\"; label = \"" (geruest-dcl-label (geruest-eintrag-name a)) "\"; fixed_width = true; }") f) (write-line " }" f) (setq i (1+ i)) ) (write-line " }" f) ) ;; Rueckgabe: Pfad der temporaeren DCL-Datei oder nil. (defun geruest-dcl-schreiben (anbauteile / pfad f) (setq pfad (vl-filename-mktemp "geruest" nil ".dcl")) (setq f (open pfad "w")) (if (null f) nil (progn (write-line "geruest : dialog {" f) (write-line " label = \"Geruest-Baugruppe konfigurieren\";" f) ;; Bereichswechsel (Rohrabhaenger/Saeulen/Wandbefestigung). DCL hat kein ;; Reiter-Tile, deshalb ein Dropdown; sein Rueckruf schliesst den Dialog ;; und die Schleife baut ihn mit dem neuen Bereich neu auf - die ;; Teilezeilen unterscheiden sich je Bereich und lassen sich zur ;; Laufzeit nicht austauschen. (write-line " : popup_list { key = \"bereich\"; label = \"Bereich:\"; width = 30; }" f) (write-line " : text { key = \"kopf\"; label = \"\"; width = 64; }" f) (write-line " : row {" f) (write-line " : popup_list { key = \"konfig\"; label = \"Konfiguration:\"; width = 40; }" f) (write-line " : button { key = \"kspeichern\"; label = \"Speichern...\"; fixed_width = true; }" f) (write-line " : button { key = \"kloeschen\"; label = \"Loeschen\"; fixed_width = true; }" f) (write-line " }" f) (write-line " : boxed_column {" f) (write-line " label = \"Basis\";" f) (write-line " : popup_list { key = \"variante\"; label = \"Variante:\"; width = 56; }" f) (write-line " : row {" f) (write-line " : edit_box { key = \"laenge\"; label = \"Laenge (mm):\"; edit_width = 10; }" f) (write-line " : popup_list { key = \"farbe\"; label = \"Farbe:\"; width = 25; }" f) (write-line " : edit_box { key = \"farbe_frei\"; label = \"eigene:\"; edit_width = 12; }" f) (write-line " }" f) (write-line " }" f) ;; Ohne Anbauteile bleiben die Spalten weg - ein leerer Cluster ist ;; in DCL nicht zulaessig (betrifft z.B. die 1-Zoll-Saeule). (if (> (length anbauteile) 0) (progn (write-line " : row {" f) (geruest-dcl-spalte f anbauteile "o" "Befestigung oben (Anzahl / Teil)") (geruest-dcl-spalte f anbauteile "u" "Befestigung unten (Anzahl / Teil)") (write-line " }" f) ) ) (write-line " ok_cancel;" f) (write-line "}" f) (close f) pfad ) ) ) ;; ============================================================ ;; DIALOGZUSTAND ;; ============================================================ ;; Die Tiles werden in Schleifen gelesen und geschrieben, ihre Anzahl steht ;; erst zur Laufzeit fest. Der Zustand liegt darum in Globals: action_tile ;; wertet seinen Rueckruf als String AUSSERHALB des lexikalischen Scopes der ;; Dialogfunktion aus, auf deren Locals kaeme er nicht. ;; Ausgangszustand einer Spalte: nichts angehakt, Mengenfeld mit der ;; JSON-Vorgabe vorbelegt (beim Klemmring also 2). (defun geruest-dlg-standard ( / erg) (setq erg nil) (foreach a *geruest-anbauteile* (setq erg (append erg (list (cons "0" (itoa (geruest-menge a)))))) ) erg ) ;; Mengenliste (nil oder Zahl je Teil) in den Tile-Zustand umsetzen. (defun geruest-mengen->tiles (mengen / erg i a) (setq erg nil i 0) (foreach m mengen (setq a (nth i *geruest-anbauteile*)) (setq erg (append erg (list (if m (cons "1" (itoa m)) (cons "0" (itoa (geruest-menge a))))))) (setq i (1+ i)) ) erg ) (defun geruest-dlg-lesen ( / i n) (setq *geruest-dlg-variante* (get_tile "variante")) (setq *geruest-dlg-laenge* (get_tile "laenge")) (setq *geruest-dlg-farbe* (get_tile "farbe")) (setq *geruest-dlg-frei* (get_tile "farbe_frei")) (setq *geruest-dlg-konfig* (get_tile "konfig")) (setq *geruest-dlg-bereich* (get_tile "bereich")) (setq n (length *geruest-anbauteile*) i 0) (setq *geruest-dlg-oben* nil *geruest-dlg-unten* nil) (while (< i n) (setq *geruest-dlg-oben* (append *geruest-dlg-oben* (list (cons (get_tile (strcat "o" (itoa i))) (get_tile (strcat "om" (itoa i))))))) (setq *geruest-dlg-unten* (append *geruest-dlg-unten* (list (cons (get_tile (strcat "u" (itoa i))) (get_tile (strcat "um" (itoa i))))))) (setq i (1+ i)) ) (princ) ) (defun geruest-dlg-schreiben ( / i n paar) (set_tile "variante" *geruest-dlg-variante*) (set_tile "laenge" *geruest-dlg-laenge*) ;; Nur setzen, wenn die Liste ueberhaupt gefuellt ist - ein Index auf eine ;; leere popup_list ist nicht definiert (Baugruppen ohne attribute-Block). (if *geruest-farb-liste* (set_tile "farbe" *geruest-dlg-farbe*)) (set_tile "farbe_frei" *geruest-dlg-frei*) (setq n (length *geruest-anbauteile*) i 0) (while (< i n) (setq paar (nth i *geruest-dlg-oben*)) (set_tile (strcat "o" (itoa i)) (car paar)) (set_tile (strcat "om" (itoa i)) (cdr paar)) (setq paar (nth i *geruest-dlg-unten*)) (set_tile (strcat "u" (itoa i)) (car paar)) (set_tile (strcat "um" (itoa i)) (cdr paar)) (setq i (1+ i)) ) (princ) ) ;; Aktuell gewaehlte Farbe als Text. (defun geruest-dlg-farbwert ( / idx) (setq idx (atoi *geruest-dlg-farbe*)) (cond ((null *geruest-farb-liste*) "") ((= idx *geruest-frei-idx*) *geruest-dlg-frei*) ((nth idx *geruest-farb-liste*) (nth idx *geruest-farb-liste*)) (T "") ) ) ;; Konfiguration anwenden und die Tiles nachziehen. Wird direkt aus dem ;; popup_list-Rueckruf aufgerufen - set_tile aendert die Anzeige im laufenden ;; Dialog, ein Neuaufbau ist nicht noetig. Index 0 = "(keine)". (defun geruest-dlg-konfig-waehlen (idx / k vidx farbe fidx) (setq *geruest-dlg-konfig* (itoa idx)) (if (<= idx 0) (progn (setq *geruest-dlg-oben* (geruest-dlg-standard)) (setq *geruest-dlg-unten* (geruest-dlg-standard)) ) (progn (setq k (nth (1- idx) *geruest-konfig-liste*)) (if k (progn (setq k (cdr k)) (setq vidx (geruest-name-index (ssg-json-get k "variante") *geruest-varianten*)) (if vidx (setq *geruest-dlg-variante* (itoa vidx)) (princ (ssg-textf "gr-konfig-variante-unbekannt" (list (ssg-json-get k "variante") (ssg-json-get k "name")))) ) (setq *geruest-dlg-laenge* (geruest-zahl-string (ssg-json-get k "laenge"))) ;; Farbe: bekannter Wert -> Listeneintrag, sonst Freitext (sofern ;; die Baugruppe das zulaesst). (setq farbe (ssg-json-get k "teilefarbe")) (setq fidx (geruest-name-farbindex farbe)) (cond (fidx (setq *geruest-dlg-farbe* (itoa fidx) *geruest-dlg-frei* "")) ((and farbe (/= farbe "") (>= *geruest-frei-idx* 0)) (setq *geruest-dlg-farbe* (itoa *geruest-frei-idx*) *geruest-dlg-frei* farbe)) ) (setq *geruest-dlg-oben* (geruest-mengen->tiles (geruest-konfig-position k "oben" *geruest-anbauteile*))) (setq *geruest-dlg-unten* (geruest-mengen->tiles (geruest-konfig-position k "unten" *geruest-anbauteile*))) ) ) ) ) (geruest-dlg-schreiben) (mode_tile "farbe_frei" (if (= (atoi *geruest-dlg-farbe*) *geruest-frei-idx*) 0 1)) (princ) ) (defun geruest-name-farbindex (wert / i idx) (setq i 0 idx nil) (foreach f *geruest-farb-liste* (if (and (null idx) (equal f wert)) (setq idx i)) (setq i (1+ i)) ) idx ) ;; Angehakte Teile einer Spalte mit gueltiger Menge einsammeln. ;; Rueckgabe: (T . ((index . menge) ...)) oder nil bei ungueltigem Mengenfeld. ;; Das fuehrende T ist noetig, weil "nichts ausgewaehlt" ein gueltiges ;; Ergebnis ist und sich sonst nicht von einem Fehler unterscheiden liesse. (defun geruest-mengen-lesen (zustand / erg i a m ok) (setq erg nil i 0 ok T) (foreach paar zustand (setq a (nth i *geruest-anbauteile*)) (if (and ok (= (car paar) "1")) (progn (setq m (geruest-menge-wert (cdr paar) (geruest-menge a))) (if m (setq erg (append erg (list (cons i m)))) (setq ok nil) ) ) ) (setq i (1+ i)) ) (if ok (cons T erg)) ) ;; Aktuellen Dialogzustand als Konfigurations-Datensatz aufbauen - in ;; derselben Form, die der Parser aus der Datei liefert, damit der Rest des ;; Moduls nicht zwischen Bibliothek und eigener Konfiguration unterscheiden ;; muss. (defun geruest-dlg-record (name) (list (cons "name" name) (cons "variante" (geruest-eintrag-name (nth (atoi *geruest-dlg-variante*) *geruest-varianten*))) (cons "laenge" *geruest-dlg-laenge*) (cons "teilefarbe" (geruest-dlg-farbwert)) (cons "oben" (geruest-dlg-teile *geruest-dlg-oben*)) (cons "unten" (geruest-dlg-teile *geruest-dlg-unten*)) ) ) (defun geruest-dlg-teile (zustand / erg i a m) (setq erg nil i 0) (foreach paar zustand (setq a (nth i *geruest-anbauteile*)) (if (= (car paar) "1") (progn (setq m (geruest-menge-wert (cdr paar) (geruest-menge a))) (if m (setq erg (append erg (list (list (cons "artikel" (geruest-eintrag-name a)) (cons "menge" m))))) ) ) ) (setq i (1+ i)) ) erg ) ;; ============================================================ ;; BENUTZERKONFIGURATIONEN SCHREIBEN ;; ============================================================ ;; Bewusst ein auf dieses Schema zugeschnittener Schreiber und kein ;; generischer JSON-Writer: beim Schreiben ist die Abbildung des Parsers ;; mehrdeutig - eine leere Liste kann aus [], {}, false oder null entstanden ;; sein. Ein generischer Writer wuerde ein Versprechen geben, das er nicht ;; halten kann. (defun geruest-teile-schreiben (f teile / n i) (setq n (length teile) i 0) (foreach e teile (setq i (1+ i)) (write-line (strcat " { \"artikel\": \"" (ssg-json-escape (ssg-json-get e "artikel")) "\", \"menge\": " (itoa (ssg-json-get e "menge")) " }" (if (< i n) "," "")) f) ) ) (defun geruest-konfig-liste-schreiben (f konfigs / n i) (setq n (length konfigs) i 0) (foreach k konfigs (setq i (1+ i)) (write-line " {" f) (write-line (strcat " \"name\": \"" (ssg-json-escape (ssg-json-get k "name")) "\",") f) (write-line (strcat " \"variante\": \"" (ssg-json-escape (ssg-json-get k "variante")) "\",") f) ;; Laenge als String: sie darf leer sein (Baugruppen ohne Laengenangabe), ;; und "laenge": ohne Wert waere kein gueltiges JSON. Der Leser ;; (geruest-zahl-string) nimmt String wie Zahl entgegen. (write-line (strcat " \"laenge\": \"" (ssg-json-escape (geruest-zahl-string (ssg-json-get k "laenge"))) "\",") f) (write-line (strcat " \"teilefarbe\": \"" (ssg-json-escape (ssg-json-get k "teilefarbe")) "\",") f) (write-line " \"oben\": [" f) (geruest-teile-schreiben f (ssg-json-get k "oben")) (write-line " ]," f) (write-line " \"unten\": [" f) (geruest-teile-schreiben f (ssg-json-get k "unten")) (write-line " ]" f) (write-line (if (< i n) " }," " }") f) ) ) ;; cfg/geruest_user.json komplett neu schreiben. (defun geruest-user-schreiben ( / pfad f n i) (setq pfad (geruest-user-pfad)) (if (null pfad) (progn (princ (ssg-text "gr-fehler-datenpfad")) nil) (progn (setq f (open pfad "w")) (if (null f) (progn (princ (ssg-textf "gr-fehler-schreiben" (list pfad))) nil) (progn (write-line "{" f) (setq n (length *geruest-user-daten*) i 0) (foreach bgruppe *geruest-user-daten* (setq i (1+ i)) (write-line (strcat " \"" (ssg-json-escape (car bgruppe)) "\": [") f) (geruest-konfig-liste-schreiben f (cdr bgruppe)) (write-line (if (< i n) " ]," " ]") f) ) (write-line "}" f) (close f) T ) ) ) ) ) ;; Eigene Konfiguration ablegen; ein gleichnamiger eigener Eintrag wird ;; ersetzt. Die Bibliothek aus geruest.json bleibt unberuehrt. (defun geruest-konfig-sichern (bg name / id liste neu ersetzt) (setq id (ssg-json-get bg "id")) (setq neu (geruest-dlg-record name)) (setq ersetzt nil) (setq liste (mapcar '(lambda (k) (if (equal (ssg-json-get k "name") name) (progn (setq ersetzt T) neu) k)) (ssg-json-get (geruest-user-daten) id))) (if (not ersetzt) (setq liste (append liste (list neu)))) (setq *geruest-user-daten* (geruest-alist-setzen (geruest-user-daten) id liste)) (if (geruest-user-schreiben) (princ (ssg-textf "gr-konfig-gespeichert" (list name))) ) ) ;; Gewaehlte eigene Konfiguration nach Rueckfrage entfernen. (defun geruest-konfig-entfernen (bg / idx k id name liste) (setq idx (atoi *geruest-dlg-konfig*)) (if (<= idx 0) (princ (ssg-text "gr-konfig-nichts-gewaehlt")) (progn (setq k (nth (1- idx) *geruest-konfig-liste*)) (cond ((null k) nil) ((null (car k)) (princ (ssg-text "gr-konfig-bibliothek-fest"))) (T (setq name (ssg-json-get (cdr k) "name")) (initget "Ja Nein") (if (equal (getkword (ssg-textf "gr-konfig-loeschen-frage" (list name))) "Ja") (progn (setq id (ssg-json-get bg "id")) (setq liste (vl-remove-if '(lambda (e) (equal (ssg-json-get e "name") name)) (ssg-json-get (geruest-user-daten) id))) (setq *geruest-user-daten* (geruest-alist-setzen (geruest-user-daten) id liste)) (if (geruest-user-schreiben) (princ (ssg-textf "gr-konfig-geloescht" (list name)))) (setq *geruest-dlg-konfig* "0") ) ) ) ) ) ) ) ;; Dialogzustand eines Bereichs sichern bzw. zurueckholen, damit ein ;; Bereichswechsel die Eingaben nicht verwirft. (defun geruest-zustand-sichern (id) (setq *geruest-zustand* (geruest-alist-setzen *geruest-zustand* id (list *geruest-dlg-variante* *geruest-dlg-laenge* *geruest-dlg-farbe* *geruest-dlg-frei* *geruest-dlg-konfig* *geruest-dlg-oben* *geruest-dlg-unten*))) ) ;; Rueckgabe T, wenn ein passender Zustand gefunden und gesetzt wurde. Die ;; Laengenpruefung faengt den Fall ab, dass die Datendatei zwischen zwei ;; Aufrufen geaendert wurde und die Teilezahl nicht mehr passt. (defun geruest-zustand-laden (id / z) (setq z (cdr (assoc id *geruest-zustand*))) (if (and z (= (length (nth 5 z)) (length *geruest-anbauteile*))) (progn (setq *geruest-dlg-variante* (nth 0 z) *geruest-dlg-laenge* (nth 1 z) *geruest-dlg-farbe* (nth 2 z) *geruest-dlg-frei* (nth 3 z) *geruest-dlg-konfig* (nth 4 z) *geruest-dlg-oben* (nth 5 z) *geruest-dlg-unten* (nth 6 z)) T ) ) ) ;; Dialog fuer einen Bereich zeigen. Rueckgabe: ;; ("OK" variante-index ((idx . menge) ...) ((idx . menge) ...) laenge farbe) ;; - drittes Element = Befestigung oben, viertes = unten ;; ("WECHSEL" bereich-index) - Nutzer hat den Bereich umgestellt ;; nil - abgebrochen (defun geruest-dialog (bg bereich-idx bereiche / dcl-pfad dat attr laenge-def farb-opts frei-opt min-l max-l fertig rueckgabe ergebnis wert-l oben-m unten-m name neu-idx) (setq *geruest-varianten* (ssg-json-get bg "geometrie_varianten")) (setq *geruest-anbauteile* (ssg-json-get bg "anbaugruppen")) (setq attr (ssg-json-get bg "attribute")) (setq laenge-def (if attr (ssg-json-get attr "Laenge"))) (setq farb-opts (if attr (ssg-json-get attr "Teilefarbe"))) (setq min-l (if laenge-def (ssg-json-get laenge-def "min"))) (setq max-l (if laenge-def (ssg-json-get laenge-def "max"))) ;; Farboptionen + freie Option ans Listenende; Index davon merkt sich der ;; Callback, um das Freitextfeld freizuschalten. (setq *geruest-farb-liste* nil *geruest-frei-idx* -1) (if farb-opts (progn (setq *geruest-farb-liste* (ssg-json-get farb-opts "optionen")) (if (ssg-json-get farb-opts "frei_erlaubt") (progn (setq frei-opt (ssg-json-get farb-opts "frei_option")) (if (null frei-opt) (setq frei-opt "Individuell")) (setq *geruest-frei-idx* (length *geruest-farb-liste*)) (setq *geruest-farb-liste* (append *geruest-farb-liste* (list frei-opt))) ) ) ) ) (setq *geruest-konfig-liste* (geruest-konfigs bg)) ;; Frueheren Stand dieses Bereichs wiederherstellen, sonst Ausgangszustand (if (null (geruest-zustand-laden (ssg-json-get bg "id"))) (progn (setq *geruest-dlg-variante* "0" *geruest-dlg-laenge* "" *geruest-dlg-farbe* "0" *geruest-dlg-frei* "" *geruest-dlg-konfig* "0") (setq *geruest-dlg-oben* (geruest-dlg-standard)) (setq *geruest-dlg-unten* (geruest-dlg-standard)) ) ) (setq fertig nil rueckgabe nil) ;; Die Dialogdefinition haengt nur an der Teileliste, nicht am Zustand - ;; einmal erzeugen und erst nach der Schleife loeschen (unload_dialog muss ;; vorher gelaufen sein). (setq dcl-pfad (geruest-dcl-schreiben *geruest-anbauteile*)) ;; Schleife: ungueltige Eingaben, Speichern und Loeschen zeigen den Dialog ;; mit dem bisherigen Stand erneut (Projektmuster, vgl. vf_linienzug). (while (not fertig) (setq dat (if dcl-pfad (load_dialog dcl-pfad) -1)) (if (or (null dcl-pfad) (< dat 0) (not (new_dialog "geruest" dat))) (progn (alert (ssg-text "gr-fehler-dcl")) (setq fertig T) ) (progn (start_list "bereich") (foreach b bereiche (add_list (geruest-titel (cdr b)))) (end_list) (set_tile "bereich" (itoa bereich-idx)) (set_tile "kopf" (ssg-textf "gr-dlg-kopf" (list (geruest-titel bg)))) (start_list "konfig") (add_list (ssg-text "gr-konfig-keine")) (foreach k *geruest-konfig-liste* (add_list (geruest-konfig-name k))) (end_list) (set_tile "konfig" *geruest-dlg-konfig*) (start_list "variante") (foreach v *geruest-varianten* (add_list (geruest-eintrag-name v))) (end_list) (if *geruest-farb-liste* (progn (start_list "farbe") (foreach f *geruest-farb-liste* (add_list f)) (end_list) ) ) ;; Alle Tiles aus dem Zustand fuellen (auch Haken und Mengenfelder) (geruest-dlg-schreiben) ;; Laenge/Farbe nur bei Baugruppen mit "attribute"-Block (if (null laenge-def) (mode_tile "laenge" 1)) (if *geruest-farb-liste* (progn (mode_tile "farbe_frei" (if (= (atoi *geruest-dlg-farbe*) *geruest-frei-idx*) 0 1)) (action_tile "farbe" "(mode_tile \"farbe_frei\" (if (= (atoi $value) *geruest-frei-idx*) 0 1))") ) (progn (mode_tile "farbe" 1) (mode_tile "farbe_frei" 1) ) ) (action_tile "konfig" "(geruest-dlg-konfig-waehlen (atoi $value))") ;; Bereichswechsel: Dialog schliessen, die Schleife in c:GERUEST baut ;; ihn mit dem neuen Bereich neu auf. (action_tile "bereich" "(geruest-dlg-lesen) (done_dialog 4)") (action_tile "accept" "(geruest-dlg-lesen) (done_dialog 1)") (action_tile "kspeichern" "(geruest-dlg-lesen) (done_dialog 2)") (action_tile "kloeschen" "(geruest-dlg-lesen) (done_dialog 3)") (action_tile "cancel" "(done_dialog 0)") (setq ergebnis (start_dialog)) (unload_dialog dat) (cond ((= ergebnis 0) (setq fertig T)) ;; Bereichswechsel: Stand dieses Bereichs sichern und an den ;; Aufrufer zurueckmelden, damit er den neuen Bereich oeffnet. ((= ergebnis 4) (setq neu-idx (atoi *geruest-dlg-bereich*)) (geruest-zustand-sichern (ssg-json-get bg "id")) (if (= neu-idx bereich-idx) nil (progn (setq rueckgabe (list "WECHSEL" neu-idx)) (setq fertig T) ) ) ) ;; Speichern: der Name wird NACH dem Schliessen abgefragt - ;; getstring funktioniert aus einem action_tile-Rueckruf heraus ;; nicht (dasselbe Muster wie die Punktwahl im VF-Assistenten). ((= ergebnis 2) (setq name (getstring T (ssg-text "gr-konfig-name"))) (if (and name (/= (ssg-cfg-trim name) "")) (progn (setq name (ssg-cfg-trim name)) (geruest-konfig-sichern bg name) (setq *geruest-konfig-liste* (geruest-konfigs bg)) ;; Gerade gespeicherten Eintrag auswaehlen, damit Liste und ;; angezeigter Stand zusammenpassen (Index 0 = ""). (setq *geruest-dlg-konfig* (itoa (geruest-konfig-index name))) ) (progn (princ (ssg-text "gr-abgebrochen")) (setq *geruest-konfig-liste* (geruest-konfigs bg)) ) ) ) ((= ergebnis 3) (geruest-konfig-entfernen bg) (setq *geruest-konfig-liste* (geruest-konfigs bg)) ) ;; Laenge pruefen - Bereichspruefung erfolgt im Projekt immer nach ;; done_dialog, DCL kann das nicht. ((and laenge-def (progn (setq wert-l (atof *geruest-dlg-laenge*)) (or (= (ssg-cfg-trim *geruest-dlg-laenge*) "") (and min-l (< wert-l min-l)) (and max-l (> wert-l max-l))))) (alert (ssg-textf "gr-alert-laenge" (list *geruest-dlg-laenge* (if min-l (rtos min-l 2 0) "0") (if max-l (rtos max-l 2 0) "-")))) ) (T (setq oben-m (geruest-mengen-lesen *geruest-dlg-oben*)) (setq unten-m (geruest-mengen-lesen *geruest-dlg-unten*)) (if (or (null oben-m) (null unten-m)) (alert (ssg-text "gr-alert-menge")) (progn (setq rueckgabe (list "OK" (atoi *geruest-dlg-variante*) (cdr oben-m) (cdr unten-m) (if laenge-def *geruest-dlg-laenge* "") (geruest-dlg-farbwert))) (setq fertig T) ) ) ) ) ) ) ) (if dcl-pfad (vl-file-delete dcl-pfad)) rueckgabe ) ;; ============================================================ ;; BLOCK BAUEN UND EINFUEGEN ;; ============================================================ ;; Eindeutiger Blockname. ssg-timestamp hat Sekundenaufloesung - bei zwei ;; Aufrufen in derselben Sekunde wird ein Zaehler angehaengt (Muster aus ;; OmniModulInsert.lsp). (defun geruest-blockname (id / bname) (setq bname (strcat "GR_" id "_" (ssg-timestamp))) (while (tblsearch "BLOCK" bname) (setq *geruest-block-counter* (1+ *geruest-block-counter*)) (setq bname (strcat "GR_" id "_" (ssg-timestamp) "_" (itoa *geruest-block-counter*))) ) bname ) ;; Dummy-Geometrie + eigene ATTDEFs zu einem Block zusammenfassen und am ;; gewaehlten Punkt einfuegen. werte = alist der berechneten Attributwerte, ;; variante = gewaehlte Geometrie-Variante (liefert ggf. eine eigene DWG). ;; Rueckgabe: (blockname . entity) oder nil. (defun geruest-block-bauen (bg variante werte pt / datei dummy lastEnt dummyEnt e ss bname blockEnt dummy-attribs attribs) ;; Eine Variante darf eine eigene Dummy-DWG mitbringen; sonst gilt die der ;; Baugruppe. (setq datei (geruest-variante-wert variante bg "dummy")) (setq dummy (geruest-dummy-pfad datei)) (if (or (null dummy) (null (findfile dummy))) (progn (princ (ssg-textf "gr-fehler-dummy" (list (if dummy dummy datei)))) nil ) (progn (setvar "ATTREQ" 0) (setvar "ATTDIA" 0) (setvar "OSMODE" 0) (setq lastEnt (entlast)) ;; Dummy bei (0,0,0) einfuegen - seine Attribute liefern u.a. die ;; LAYER-Vorgabe. (command "_.INSERT" dummy (list 0.0 0.0 0.0) 1 1 0) (setq dummyEnt (entlast)) (setq dummy-attribs (ssg-attrib-read dummyEnt)) ;; Unser Schema gewinnt an Struktur, die Dummy-Werte an Inhalt: ;; ssg-attrib-merge legt alle Tags aus *geruest-attrib-defs* an und ;; uebernimmt zusaetzlich alle Tags der Dummy-DWG. (setq attribs (ssg-attrib-merge dummy-attribs *geruest-attrib-defs*)) (foreach paar werte (if (assoc (car paar) attribs) (setq attribs (subst paar (assoc (car paar) attribs) attribs)) (setq attribs (append attribs (list paar))) ) ) (ssg-attrib-make-defs (ssg-attrib-alist-to-defs attribs) 50.0) ;; Alles Neue seit lastEnt einsammeln (Dummy-INSERT + ATTDEFs) (setq ss (ssadd)) (setq e (if lastEnt (entnext lastEnt) (entnext))) (while e (ssadd e ss) (setq e (entnext e)) ) (setq bname (geruest-blockname (ssg-json-get bg "id"))) (command "_.-BLOCK" bname (list 0.0 0.0 0.0) ss "") ;; Stand VOR dem Einfuegen merken: bricht der Nutzer die Drehung mit ESC ;; ab, entsteht kein neues INSERT und (entlast) zeigt auf ein voellig ;; fremdes Objekt - ohne diesen Vergleich wuerden dessen Attribute ;; ueberschrieben. (setq lastEnt (entlast)) ;; pause = Drehwinkel interaktiv am Cursor (command "_.INSERT" bname pt 1 1 pause) ;; Laufende Einfuegung sicher beenden (z.B. ESC waehrend der Drehung) (if (> (getvar "CMDACTIVE") 0) (command)) (if (> (getvar "CMDACTIVE") 0) (command)) (setq blockEnt (entlast)) (if (and blockEnt (not (eq blockEnt lastEnt)) (= (cdr (assoc 0 (entget blockEnt))) "INSERT")) (progn (ssg-attrib-set-on blockEnt attribs) (ssg-block-layer-vorgabe blockEnt bname attribs) (cons bname blockEnt) ) ) ) ) ) ;; ============================================================ ;; ABLAUF ;; ============================================================ ;; Artikelnummern einer Befestigungsauswahl ((index . menge) ...). (defun geruest-auswahl-artnr (auswahl anbauteile / erg) (setq erg nil) (foreach paar auswahl (setq erg (append erg (geruest-artikelnummern-n (nth (car paar) anbauteile) (cdr paar)))) ) erg ) ;; Namensteile einer Befestigungsauswahl fuer die BEZEICHNUNG, ;; z.B. ("oben 2x ROHRKLAMMER 1\" KPL. VERTIKAL"). (defun geruest-auswahl-namen (auswahl anbauteile position / erg) (setq erg nil) (foreach paar auswahl (setq erg (append erg (list (strcat position " " (itoa (cdr paar)) "x " (geruest-eintrag-name (nth (car paar) anbauteile)))))) ) erg ) ;; Ausgewaehlte Konfiguration einfuegen. ;; wahl = (variante-index oben unten laenge farbe) - die Dialog-Rueckgabe ohne ;; das fuehrende "OK". (defun geruest-einfuegen (bg wahl / varianten anbauteile variante teileart artnr bezeichnung teile-namen werte pt ergebnis) (setq varianten (ssg-json-get bg "geometrie_varianten")) (setq anbauteile (ssg-json-get bg "anbaugruppen")) (setq variante (nth (car wahl) varianten)) ;; TEILEART kann die Variante vorgeben (Saeule 1 Zoll vs. 2 Zoll) - ;; sonst gilt der Wert der Baugruppe. (setq teileart (geruest-variante-wert variante bg "teileart")) ;; ARTINR: jede Sivas-ID so oft wie die gewaehlte Stueckzahl, erst die ;; Basis, dann Befestigung oben, dann unten. Dasselbe Teil an beiden ;; Positionen erscheint entsprechend mehrfach. (setq artnr (geruest-artikelnummern variante)) (setq artnr (append artnr (geruest-auswahl-artnr (cadr wahl) anbauteile))) (setq artnr (append artnr (geruest-auswahl-artnr (caddr wahl) anbauteile))) ;; BEZEICHNUNG: mit " + " verketten - die Artikelbezeichnungen enthalten ;; selbst Kommas ("ROHR R 1\" 33,7 x 2,6"). (setq teile-namen (list teileart (geruest-eintrag-name variante))) (setq teile-namen (append teile-namen (geruest-auswahl-namen (cadr wahl) anbauteile (ssg-text "gr-position-oben")))) (setq teile-namen (append teile-namen (geruest-auswahl-namen (caddr wahl) anbauteile (ssg-text "gr-position-unten")))) (setq bezeichnung (ssg-join teile-namen " + ")) (setq werte (list (cons "ARTINR" (ssg-join artnr ",")) (cons "BEZEICHNUNG" bezeichnung) (cons "TEILEART" teileart))) (if (/= (nth 3 wahl) "") (setq werte (append werte (list (cons "LAENGE" (nth 3 wahl)))))) (if (/= (nth 4 wahl) "") (setq werte (append werte (list (cons "TEILEFARBE" (nth 4 wahl)))))) (setq pt (getpoint (ssg-text "gr-prompt-einfuegepunkt"))) (if (null pt) (princ (ssg-text "gr-abgebrochen")) (progn (ssg-start "Geruest" '(("OSMODE") ("ATTREQ") ("ATTDIA"))) (setq ergebnis (geruest-block-bauen bg variante werte pt)) (ssg-end) (if ergebnis (princ (ssg-textf "gr-fertig" (list teileart (car ergebnis)))) ) ) ) (princ) ) ;; Ein Dialog fuer alle Geruest-Bereiche. Der Bereichswechsel laeuft ueber ;; diese Schleife, weil der Dialog dafuer neu aufgebaut werden muss. (defun c:GERUEST ( / bereiche idx bg erg weiter) (setq *geruest-zustand* nil) (setq bereiche (geruest-baugruppen-liste)) (if (null bereiche) (princ (ssg-text "gr-fehler-keine-baugruppen")) (progn (setq idx 0 weiter T) (while weiter (setq bg (cdr (nth idx bereiche))) (cond ((null (ssg-json-get bg "geometrie_varianten")) (princ (ssg-textf "gr-fehler-keine-varianten" (list (ssg-json-get bg "id")))) (setq weiter nil) ) (T (setq erg (geruest-dialog bg idx bereiche)) (cond ((null erg) (princ (ssg-text "gr-abgebrochen")) (setq weiter nil)) ((equal (car erg) "WECHSEL") (setq idx (cadr erg))) (T (setq weiter nil) (geruest-einfuegen bg (cdr erg))) ) ) ) ) ) ) (princ) ) (princ "\nGeruestInsert.lsp geladen. Befehl: GERUEST") (princ)