[ADD] Block- und Text-Werkzeuge aus Walz (ACADSST) uebernommen
Neue Module ssg_blocktools.lsp (SSG_BLOCK_COUNT, SSG_BLOCK_DELETE, SSG_ATTR_ERSETZEN) und ssg_texttools.lsp (SSG_TEXT_ERSETZEN, SSG_TEXT_PARALLEL, SSG_TEXT_HOEHE, SSG_TEXT_STIL) sowie der generische Eingabe-Wrapper ssg_input.lsp, dazu Menue-/Lade-Integration, zweisprachige Texte und Unit-Tests fuer die reinen Kerne. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -323,6 +323,63 @@ Benutzerfreundliche BricsCAD-Befehle für Layer-Operationen. Alle Befehle sicher
|
||||
|
||||
---
|
||||
|
||||
### `ssg_input.lsp` – Generische Eingabe-Wrapper
|
||||
|
||||
Abfragen mit Vorgabewert (`<..>` im Prompt, Enter = Vorgabe). Steht neben den VF-spezifischen `vfl-in-*` (`vf_linienzug.lsp`); diese bleiben unveraendert. Kein Journal, aber ein optionaler Hook. ESC bricht wie ueblich ueber `*error*` ab.
|
||||
|
||||
| Funktion | Beschreibung |
|
||||
| --- | --- |
|
||||
| `ssg-in-real text default` | Reelle Zahl (`getreal`), Vorgabe ohne ueberfluessige Nullen angezeigt |
|
||||
| `ssg-in-int text default` | Ganzzahl (`getint`) |
|
||||
| `ssg-in-string text default` | String mit Leerzeichen; Enter ohne Eingabe liefert die Vorgabe (ohne Vorgabe `nil`) |
|
||||
| `ssg-in-point text default base` | Punkt, `base` = Gummiband-Basispunkt oder `nil` |
|
||||
| `ssg-in-dist text default base` | Abstand (`getdist`) |
|
||||
| `ssg-in-keyword text schluessel default` | Schluesselwort im `initget`-Format, z.B. `"Alle Auswahl"` |
|
||||
| `ssg-in-yesno text default` | Ja/Nein, **T = Ja**; `default` T = Enter bedeutet Ja. Woerter aus `ssg-text "in-yesno-keys"` |
|
||||
| `ssg-in-default wert default`, `ssg-in-fmt-real`, `ssg-in-fmt-pt`, `ssg-in-prompt`, `ssg-in-first-word`, `ssg-in-second-word` | Reine Hilfsfunktionen (in `tests/test_unit.lsp` getestet) |
|
||||
|
||||
Hook (z.B. fuer ein Eingabe-Journal): `(setq *ssg-in-hook* 'meine-funktion)` mit `(defun meine-funktion (art prompt wert) ...)`; `art` ist `"REAL"`, `"INT"`, `"STRING"`, `"POINT"`, `"DIST"`, `"KEYWORD"` oder `"YESNO"`. Ein Hook, der einen Fehler wirft, wird abgeschaltet.
|
||||
|
||||
---
|
||||
|
||||
### `ssg_blocktools.lsp` – Block-Werkzeuge
|
||||
|
||||
Ursprung: ACADSST `TOOLS.LSP` (`BLKANZAHL`, `BLKENTF`), `DINGEN2` (`g-bli`), `ssg.lsp` (`suchen-aendern`). Arbeitet im **aktuellen Layout-Reiter**. Blocknamen werden ueber den wirksamen Namen verglichen (dynamische Bloecke); Muster mit `wcmatch` (`*`, `?`, `#`, ohne Gross-/Kleinschreibung).
|
||||
|
||||
| Befehl | Beschreibung |
|
||||
| --- | --- |
|
||||
| `SSG_BLOCK_COUNT` | Block anklicken, `Name` fuer ein Muster, oder Enter fuer eine Statistik aller Bloecke |
|
||||
| `SSG_BLOCK_DELETE` | Alle Einfuegungen eines Blocks/Musters loeschen; Rueckfrage (Vorgabe Nein), Einfuegungen auf gesperrten Layern bleiben stehen; eine Undo-Gruppe |
|
||||
| `SSG_ATTR_ERSETZEN` | Attributwerte suchen/ersetzen: Bereich (Alle mit Blockname-Muster / Auswahl), Tag-Muster, Suchtext, Ersatz, Modus Teil (Teilstring) oder Gesamt (ganzer Wert). Zeigt vorab die Anzahl und fragt nach |
|
||||
|
||||
| Funktion | Beschreibung |
|
||||
| --- | --- |
|
||||
| `ssg-bt-inserts muster` | Entity-Liste aller Einfuegungen im Layout (optional nach Muster) |
|
||||
| `ssg-bt-statistik muster` | `((NAME . ANZAHL) ...)` alphabetisch |
|
||||
| `ssg-bt-attr-ersetzen-ent ent tag suche ersatz teil-p probe-p` | Attribute EINER Einfuegung ersetzen bzw. nur zaehlen (`probe-p`); Rueckgabe Anzahl |
|
||||
| `ssg-bt-attr-ersetzen-liste ents tag suche ersatz teil-p probe-p` | Dasselbe fuer eine Entity-Liste |
|
||||
| `ssg-bt-wert-neu wert suche ersatz teil-p` | Reiner Kern: neuer Wert oder `nil` (unveraendert); beachtet Gross-/Kleinschreibung |
|
||||
| `ssg-bt-name-passt-p`, `ssg-bt-zaehle-namen`, `ssg-bt-muster-escape` | Reine Hilfsfunktionen (getestet) |
|
||||
|
||||
---
|
||||
|
||||
### `ssg_texttools.lsp` – Text-Werkzeuge
|
||||
|
||||
Ursprung: ACADSST `CHGTEXT.LSP`, `PARTEXT.LSP`, `ALTHOEHE.LSP`, `ALTSTIL.LSP`. Laden **nach** `ssg_blocktools` (nutzt `ssg-bt-wert-neu` und `ssg-bt-attr-ersetzen-liste`). Arbeitet in der XY-Ebene des Welt-KS.
|
||||
|
||||
| Befehl | Beschreibung |
|
||||
| --- | --- |
|
||||
| `SSG_TEXT_ERSETZEN` | Suchen/Ersetzen in TEXT, MTEXT **und** Block-Attributen; Bereich Alle (Layout) oder Auswahl; Vorschau mit Anzahl, Rueckfrage |
|
||||
| `SSG_TEXT_PARALLEL` | Linie/Polylinie/Bogen anklicken, Text wird parallel (lesbar, nie auf dem Kopf) mit Abstand gesetzt; Hoehe, Abstand und letzter Text werden fuer die Sitzung gemerkt; Enter beendet |
|
||||
| `SSG_TEXT_HOEHE` | Texthoehe gewaehlter TEXT/MTEXT aendern |
|
||||
| `SSG_TEXT_STIL` | Textstil gewaehlter TEXT/MTEXT aendern (Stil muss existieren) |
|
||||
|
||||
Reine Kerne (getestet): `ssg-tt-lesbarer-winkel` (Winkel 90 Grad bis 270 Grad um 180 Grad drehen, Ergebnis in [0, 2 pi)), `ssg-tt-versetzt`.
|
||||
|
||||
Nicht uebernommen aus Walz: `Export`/`Import` von Texten (besser per Python/ezdxf), `KREISTXT`, `TXTBOXED`, `CHTEXT`/`ASCTEXT`/`PTEXT` (Autodesk 1990, durch BricsCAD-Standard ersetzt).
|
||||
|
||||
---
|
||||
|
||||
### `ssg_load.lsp` – Laderoutine
|
||||
|
||||
Lädt alle Module in der richtigen Reihenfolge. Ermittelt den Pfad automatisch über `findfile`. Ruft direkt nach `ssg_core.lsp` die Funktion `ssg-load-config` auf, damit die JSON-Konfiguration für alle nachfolgenden Module verfügbar ist.
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
;; ============================================================
|
||||
;; SSG_BLOCKTOOLS.LSP - Block-Werkzeuge fuer die aktuelle Zeichnung
|
||||
;;
|
||||
;; Ursprung: ACADSST/MENU/TOOLS.LSP (BLKANZAHL, BLKENTF), DINGEN2
|
||||
;; (g-bli) und ssg.lsp (suchen-aendern) - neu geschrieben im ssg-Stil
|
||||
;; (Undo-Gruppe, i18n, Ja/Nein-Rueckfrage, keine Globals).
|
||||
;;
|
||||
;; Befehle:
|
||||
;; SSG_BLOCK_COUNT Einfuegungen zaehlen (ein Block, Namensmuster
|
||||
;; oder Statistik aller Bloecke)
|
||||
;; SSG_BLOCK_DELETE Alle Einfuegungen eines Blocks/Namensmusters
|
||||
;; loeschen (mit Rueckfrage)
|
||||
;; SSG_ATTR_ERSETZEN Attributwerte zeichnungsweit oder in einer
|
||||
;; Auswahl suchen und ersetzen (mit Vorschau)
|
||||
;;
|
||||
;; Blocknamen werden ueber den WIRKSAMEN Namen verglichen (dynamische
|
||||
;; Bloecke: EffectiveName statt "*U12"). Muster arbeiten mit wcmatch
|
||||
;; (Platzhalter * ? #, ohne Beachtung der Gross-/Kleinschreibung).
|
||||
;; Es wird nur der aktuelle Layout-Reiter (Modell ODER Papierbereich)
|
||||
;; durchsucht.
|
||||
;;
|
||||
;; Setzt ssg_core.lsp, ssg_lang.lsp und ssg_input.lsp voraus.
|
||||
;; ============================================================
|
||||
|
||||
(vl-load-com)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; REINE HILFSFUNKTIONEN (in test_unit getestet)
|
||||
;; ------------------------------------------------------------
|
||||
|
||||
;; T, wenn name auf das wcmatch-Muster passt (ohne Gross-/Kleinschreibung).
|
||||
;; muster nil oder "" -> alle Namen passen.
|
||||
(defun ssg-bt-name-passt-p (name muster)
|
||||
(if (or (null muster) (= muster ""))
|
||||
T
|
||||
(if (wcmatch (strcase name) (strcase muster)) T nil)
|
||||
)
|
||||
)
|
||||
|
||||
;; Liste von Namen -> Alist ((NAME . ANZAHL) ...), alphabetisch sortiert
|
||||
;; (ohne Beachtung der Gross-/Kleinschreibung).
|
||||
(defun ssg-bt-zaehle-namen (namen / alist eintrag)
|
||||
(foreach name namen
|
||||
(setq eintrag (assoc name alist))
|
||||
(if eintrag
|
||||
(setq alist (subst (cons name (1+ (cdr eintrag))) eintrag alist))
|
||||
(setq alist (cons (cons name 1) alist))
|
||||
)
|
||||
)
|
||||
(vl-sort alist '(lambda (a b) (< (strcase (car a)) (strcase (car b)))))
|
||||
)
|
||||
|
||||
;; Sonderzeichen eines Blocknamens fuer wcmatch maskieren (Backquote), damit
|
||||
;; ein per Pick gewaehlter Name nur sich selbst trifft.
|
||||
(defun ssg-bt-muster-escape (name / res i c)
|
||||
(setq res "" i 1)
|
||||
(while (<= i (strlen name))
|
||||
(setq c (substr name i 1))
|
||||
(if (vl-string-search c "#@.*?~[],`")
|
||||
(setq res (strcat res "`"))
|
||||
)
|
||||
(setq res (strcat res c)
|
||||
i (1+ i))
|
||||
)
|
||||
res
|
||||
)
|
||||
|
||||
;; Muster ohne Maskier-Backquotes (fuer Meldungen)
|
||||
(defun ssg-bt-muster-anzeige (muster)
|
||||
(ssg-str-replace-all "" "`" muster)
|
||||
)
|
||||
|
||||
;; Neuer Attributwert oder nil, wenn der Wert unveraendert bleibt.
|
||||
;; teil-p = T : suche wird als Teilstring ueberall ersetzt
|
||||
;; teil-p = nil: nur ersetzen, wenn der GESAMTE Wert gleich suche ist
|
||||
;; Leere suche aendert nichts. Gross-/Kleinschreibung wird beachtet.
|
||||
(defun ssg-bt-wert-neu (wert suche ersatz teil-p)
|
||||
(cond
|
||||
((or (null suche) (= suche "") (null wert)) nil)
|
||||
(teil-p
|
||||
(if (vl-string-search suche wert)
|
||||
(ssg-str-replace-all ersatz suche wert)
|
||||
nil
|
||||
)
|
||||
)
|
||||
((= wert suche) ersatz)
|
||||
(t nil)
|
||||
)
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; ZEICHNUNGSZUGRIFF
|
||||
;; ------------------------------------------------------------
|
||||
|
||||
;; Wirksamer Blockname einer Einfuegung (dynamische Bloecke beachten)
|
||||
(defun ssg-bt-effname (ent / res)
|
||||
(setq res (vl-catch-all-apply 'vla-get-effectivename
|
||||
(list (vlax-ename->vla-object ent))))
|
||||
(if (vl-catch-all-error-p res)
|
||||
(cdr (assoc 2 (entget ent)))
|
||||
res
|
||||
)
|
||||
)
|
||||
|
||||
;; T, wenn der Layer der Entity gesperrt ist
|
||||
(defun ssg-bt-layer-gesperrt-p (ent / lay)
|
||||
(setq lay (tblsearch "LAYER" (cdr (assoc 8 (entget ent)))))
|
||||
(and lay (= 4 (logand 4 (cdr (assoc 70 lay)))))
|
||||
)
|
||||
|
||||
;; Alle Einfuegungen im aktuellen Layout, optional gefiltert nach Namensmuster.
|
||||
;; Rueckgabe: Liste von Entity-Namen (kann leer sein).
|
||||
(defun ssg-bt-inserts (muster / ss i ent res)
|
||||
(setq ss (ssget "_X" (list '(0 . "INSERT") (cons 410 (getvar "CTAB")))))
|
||||
(if ss
|
||||
(progn
|
||||
(setq i 0)
|
||||
(while (setq ent (ssname ss i))
|
||||
(if (ssg-bt-name-passt-p (ssg-bt-effname ent) muster)
|
||||
(setq res (cons ent res))
|
||||
)
|
||||
(setq i (1+ i))
|
||||
)
|
||||
)
|
||||
)
|
||||
(reverse res)
|
||||
)
|
||||
|
||||
;; Statistik: ((NAME . ANZAHL) ...) fuer alle Einfuegungen passend zum Muster
|
||||
(defun ssg-bt-statistik (muster)
|
||||
(ssg-bt-zaehle-namen (mapcar 'ssg-bt-effname (ssg-bt-inserts muster)))
|
||||
)
|
||||
|
||||
;; Block per Pick oder Namensmuster waehlen.
|
||||
;; Rueckgabe: Namensmuster (String) oder nil bei Enter ("alle").
|
||||
(defun ssg-bt-muster-waehlen (text / sel ed)
|
||||
(initget "Name")
|
||||
(setq sel (entsel text))
|
||||
(cond
|
||||
((null sel) nil)
|
||||
((= (type sel) 'STR)
|
||||
(setq sel (getstring T (ssg-text "bt-prompt-muster")))
|
||||
(if (= sel "") nil sel)
|
||||
)
|
||||
(t
|
||||
(setq ed (entget (car sel)))
|
||||
(if (= (cdr (assoc 0 ed)) "INSERT")
|
||||
(ssg-bt-muster-escape (ssg-bt-effname (car sel)))
|
||||
(progn (prompt (ssg-text "bt-kein-block")) nil)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; Attribute EINER Einfuegung ersetzen (oder nur zaehlen, wenn probe-p).
|
||||
;; tag = wcmatch-Muster fuer den Attribut-Tag ("*" = alle).
|
||||
;; Rueckgabe: Anzahl betroffener Attribute.
|
||||
(defun ssg-bt-attr-ersetzen-ent (ent tag suche ersatz teil-p probe-p
|
||||
/ e ed neu n)
|
||||
(setq n 0
|
||||
e (entnext ent))
|
||||
(while (and e
|
||||
(= "ATTRIB" (cdr (assoc 0 (setq ed (entget e))))))
|
||||
(if (and (ssg-bt-name-passt-p (cdr (assoc 2 ed)) tag)
|
||||
(setq neu (ssg-bt-wert-neu (cdr (assoc 1 ed)) suche ersatz teil-p)))
|
||||
(progn
|
||||
(setq n (1+ n))
|
||||
(if (not probe-p)
|
||||
(entmod (subst (cons 1 neu) (assoc 1 ed) ed))
|
||||
)
|
||||
)
|
||||
)
|
||||
(setq e (entnext e))
|
||||
)
|
||||
(if (and (> n 0) (not probe-p)) (entupd ent))
|
||||
n
|
||||
)
|
||||
|
||||
;; Attribute einer Liste von Einfuegungen ersetzen. Rueckgabe: Anzahl.
|
||||
(defun ssg-bt-attr-ersetzen-liste (ents tag suche ersatz teil-p probe-p / n)
|
||||
(setq n 0)
|
||||
(foreach ent ents
|
||||
(setq n (+ n (ssg-bt-attr-ersetzen-ent ent tag suche ersatz teil-p probe-p)))
|
||||
)
|
||||
n
|
||||
)
|
||||
|
||||
;; Auswahlsatz -> Liste von Entity-Namen (nur INSERT)
|
||||
(defun ssg-bt-ss-inserts (ss / i ent res)
|
||||
(if ss
|
||||
(progn
|
||||
(setq i 0)
|
||||
(while (setq ent (ssname ss i))
|
||||
(if (= (cdr (assoc 0 (entget ent))) "INSERT")
|
||||
(setq res (cons ent res))
|
||||
)
|
||||
(setq i (1+ i))
|
||||
)
|
||||
)
|
||||
)
|
||||
(reverse res)
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; BEFEHLE
|
||||
;; ------------------------------------------------------------
|
||||
|
||||
(defun c:SSG_BLOCK_COUNT ( / muster stat summe)
|
||||
(setq muster (ssg-bt-muster-waehlen (ssg-text "bt-prompt-waehlen-count")))
|
||||
(setq stat (ssg-bt-statistik muster))
|
||||
(cond
|
||||
((null stat)
|
||||
(prompt (if muster
|
||||
(ssg-textf "bt-count-keine" (list (ssg-bt-muster-anzeige muster)))
|
||||
(ssg-text "bt-count-keine-alle")))
|
||||
)
|
||||
((and muster (null (cdr stat)))
|
||||
(prompt (ssg-textf "bt-count-ergebnis" (list (cdar stat) (caar stat))))
|
||||
)
|
||||
(t
|
||||
(setq summe 0)
|
||||
(foreach z stat
|
||||
(prompt (ssg-textf "bt-count-zeile" (list (car z) (cdr z))))
|
||||
(setq summe (+ summe (cdr z)))
|
||||
)
|
||||
(prompt (ssg-textf "bt-count-summe" (list summe (length stat))))
|
||||
)
|
||||
)
|
||||
(princ)
|
||||
)
|
||||
|
||||
(defun c:SSG_BLOCK_DELETE ( / muster ents frei gesperrt n)
|
||||
(setq muster (ssg-bt-muster-waehlen (ssg-text "bt-prompt-waehlen-delete")))
|
||||
(if (null muster)
|
||||
(prompt (ssg-text "bt-delete-kein-muster"))
|
||||
(progn
|
||||
(setq ents (ssg-bt-inserts muster))
|
||||
(foreach ent ents
|
||||
(if (ssg-bt-layer-gesperrt-p ent)
|
||||
(setq gesperrt (cons ent gesperrt))
|
||||
(setq frei (cons ent frei))
|
||||
)
|
||||
)
|
||||
(cond
|
||||
((null ents)
|
||||
(prompt (ssg-textf "bt-count-keine" (list (ssg-bt-muster-anzeige muster)))))
|
||||
((null frei)
|
||||
(prompt (ssg-textf "bt-delete-alle-gesperrt" (list (length gesperrt)))))
|
||||
((ssg-in-yesno (ssg-textf "bt-delete-frage" (list (length frei) (ssg-bt-muster-anzeige muster))) nil)
|
||||
(ssg-start (ssg-text "bt-delete-titel") nil)
|
||||
(setq n 0)
|
||||
(foreach ent frei
|
||||
(if (entdel ent) (setq n (1+ n)))
|
||||
)
|
||||
(ssg-end)
|
||||
(prompt (ssg-textf "bt-delete-ergebnis" (list n)))
|
||||
(if gesperrt
|
||||
(prompt (ssg-textf "bt-delete-gesperrt" (list (length gesperrt)))))
|
||||
)
|
||||
(t (prompt (ssg-text "bt-abgebrochen")))
|
||||
)
|
||||
)
|
||||
)
|
||||
(princ)
|
||||
)
|
||||
|
||||
(defun c:SSG_ATTR_ERSETZEN ( / k-bereich k-modus bereich ents muster tag suche ersatz modus teil-p n)
|
||||
(setq k-bereich (ssg-text "in-keys-bereich")
|
||||
k-modus (ssg-text "in-keys-modus")
|
||||
bereich (ssg-in-keyword (ssg-text "bt-attr-bereich") k-bereich
|
||||
(ssg-in-first-word k-bereich)))
|
||||
(if (= bereich (ssg-in-first-word k-bereich))
|
||||
(progn
|
||||
(setq muster (ssg-in-string (ssg-text "bt-attr-muster") "*"))
|
||||
(setq ents (ssg-bt-inserts muster))
|
||||
)
|
||||
(progn
|
||||
(prompt (ssg-text "bt-attr-auswahl"))
|
||||
(setq ents (ssg-bt-ss-inserts (ssget '((0 . "INSERT")))))
|
||||
)
|
||||
)
|
||||
(cond
|
||||
((null ents) (prompt (ssg-text "bt-attr-keine-bloecke")))
|
||||
(t
|
||||
(setq tag (ssg-in-string (ssg-text "bt-attr-tag") "*")
|
||||
suche (ssg-in-string (ssg-text "bt-attr-suche") nil))
|
||||
(if (or (null suche) (= suche ""))
|
||||
(prompt (ssg-text "bt-abgebrochen"))
|
||||
(progn
|
||||
(setq ersatz (ssg-in-string (ssg-text "bt-attr-ersatz") "")
|
||||
modus (ssg-in-keyword (ssg-text "bt-attr-modus") k-modus
|
||||
(ssg-in-first-word k-modus))
|
||||
teil-p (= modus (ssg-in-first-word k-modus)))
|
||||
(setq n (ssg-bt-attr-ersetzen-liste ents tag suche ersatz teil-p T))
|
||||
(cond
|
||||
((= n 0) (prompt (ssg-text "bt-attr-nichts")))
|
||||
((ssg-in-yesno (ssg-textf "bt-attr-frage" (list n (length ents))) T)
|
||||
(ssg-start (ssg-text "bt-attr-titel") nil)
|
||||
(setq n (ssg-bt-attr-ersetzen-liste ents tag suche ersatz teil-p nil))
|
||||
(ssg-end)
|
||||
(prompt (ssg-textf "bt-attr-ergebnis" (list n))))
|
||||
(t (prompt (ssg-text "bt-abgebrochen")))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(princ)
|
||||
)
|
||||
|
||||
(princ)
|
||||
@@ -0,0 +1,162 @@
|
||||
;; ============================================================
|
||||
;; SSG_INPUT.LSP - Generische Eingabe-Wrapper (ssg-in-*)
|
||||
;;
|
||||
;; Allgemeingueltige Abfragen mit Vorgabewert, Anzeige "<Vorgabe>" im
|
||||
;; Prompt und Enter = Vorgabe (Idee von g_in/g_ky aus den ACADSST-
|
||||
;; Makros). Steht NEBEN den VF-spezifischen vfl-in-* aus
|
||||
;; vf_linienzug.lsp; diese bleiben unveraendert.
|
||||
;;
|
||||
;; Alle Funktionen liefern den eingegebenen Wert oder die Vorgabe.
|
||||
;; ESC bricht wie ueblich ueber *error* ab (z.B. ssg-errhan).
|
||||
;; Ist kein Wert eingegeben und keine Vorgabe da, ist die Rueckgabe nil.
|
||||
;;
|
||||
;; Optionaler Hook (z.B. fuer ein Eingabe-Journal):
|
||||
;; (setq *ssg-in-hook* 'meine-funktion)
|
||||
;; (defun meine-funktion (art prompt wert) ...) ;; art = "REAL" "INT"
|
||||
;; ;; "STRING" "POINT"
|
||||
;; ;; "DIST" "KEYWORD"
|
||||
;; ;; "YESNO"
|
||||
;; Ein Hook, der einen Fehler wirft, wird abgeschaltet.
|
||||
;;
|
||||
;; Setzt ssg_core.lsp (und fuer ssg-in-yesno ssg_lang.lsp) voraus.
|
||||
;; ============================================================
|
||||
|
||||
(vl-load-com)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; REINE HILFSFUNKTIONEN (ohne Zeichnung, in test_unit getestet)
|
||||
;; ------------------------------------------------------------
|
||||
|
||||
;; Vorgabe einsetzen, wenn kein Wert eingegeben wurde
|
||||
(defun ssg-in-default (wert default)
|
||||
(if wert wert default)
|
||||
)
|
||||
|
||||
;; Reelle Zahl ohne ueberfluessige Nullen: 5.0 -> "5", 2.50 -> "2.5"
|
||||
(defun ssg-in-fmt-real (v / s)
|
||||
(setq s (rtos v 2 6))
|
||||
(if (vl-string-position 46 s)
|
||||
(progn
|
||||
(while (= (substr s (strlen s)) "0")
|
||||
(setq s (substr s 1 (1- (strlen s))))
|
||||
)
|
||||
(if (= (substr s (strlen s)) ".")
|
||||
(setq s (substr s 1 (1- (strlen s))))
|
||||
)
|
||||
)
|
||||
)
|
||||
s
|
||||
)
|
||||
|
||||
;; Punkt als "x,y,z" (fehlende Z-Werte als 0)
|
||||
(defun ssg-in-fmt-pt (p)
|
||||
(strcat (ssg-in-fmt-real (car p)) ","
|
||||
(ssg-in-fmt-real (cadr p)) ","
|
||||
(ssg-in-fmt-real (if (caddr p) (caddr p) 0.0)))
|
||||
)
|
||||
|
||||
;; Prompt aufbauen: "<text> <default>: " bzw. "<text>: " ohne Vorgabe
|
||||
(defun ssg-in-prompt (text default-str)
|
||||
(strcat text
|
||||
(if default-str (strcat " <" default-str ">") "")
|
||||
": ")
|
||||
)
|
||||
|
||||
;; Erstes Wort eines Schluesselwort-Strings: "Ja Nein" -> "Ja"
|
||||
(defun ssg-in-first-word (schluessel / pos)
|
||||
(if (setq pos (vl-string-search " " schluessel))
|
||||
(substr schluessel 1 pos)
|
||||
schluessel
|
||||
)
|
||||
)
|
||||
|
||||
;; Zweites Wort: "Ja Nein" -> "Nein"
|
||||
(defun ssg-in-second-word (schluessel / pos)
|
||||
(if (setq pos (vl-string-search " " schluessel))
|
||||
(substr schluessel (+ pos 2))
|
||||
""
|
||||
)
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; HOOK
|
||||
;; ------------------------------------------------------------
|
||||
(defun ssg-in-notify (art text wert / res)
|
||||
(if *ssg-in-hook*
|
||||
(progn
|
||||
(setq res (vl-catch-all-apply *ssg-in-hook* (list art text wert)))
|
||||
(if (vl-catch-all-error-p res) (setq *ssg-in-hook* nil))
|
||||
)
|
||||
)
|
||||
wert
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; ABFRAGEN
|
||||
;; text = Prompt ohne Doppelpunkt, z.B. "\nHoehe"
|
||||
;; ------------------------------------------------------------
|
||||
|
||||
(defun ssg-in-real (text default / w)
|
||||
(setq w (getreal (ssg-in-prompt text (if default (ssg-in-fmt-real default)))))
|
||||
(ssg-in-notify "REAL" text (ssg-in-default w default))
|
||||
)
|
||||
|
||||
(defun ssg-in-int (text default / w)
|
||||
(setq w (getint (ssg-in-prompt text (if default (itoa default)))))
|
||||
(ssg-in-notify "INT" text (ssg-in-default w default))
|
||||
)
|
||||
|
||||
;; String (mit Leerzeichen). Enter ohne Eingabe -> Vorgabe.
|
||||
(defun ssg-in-string (text default / w)
|
||||
(setq w (getstring T (ssg-in-prompt text default)))
|
||||
(if (= w "") (setq w nil))
|
||||
(ssg-in-notify "STRING" text (ssg-in-default w default))
|
||||
)
|
||||
|
||||
;; Punkt. base = Gummiband-Basispunkt oder nil, default = Punkt oder nil.
|
||||
(defun ssg-in-point (text default base / w)
|
||||
(setq w (if base
|
||||
(getpoint base (ssg-in-prompt text (if default (ssg-in-fmt-pt default))))
|
||||
(getpoint (ssg-in-prompt text (if default (ssg-in-fmt-pt default))))
|
||||
))
|
||||
(ssg-in-notify "POINT" text (ssg-in-default w default))
|
||||
)
|
||||
|
||||
;; Abstand. base = Basispunkt oder nil.
|
||||
(defun ssg-in-dist (text default base / w)
|
||||
(setq w (if base
|
||||
(getdist base (ssg-in-prompt text (if default (ssg-in-fmt-real default))))
|
||||
(getdist (ssg-in-prompt text (if default (ssg-in-fmt-real default))))
|
||||
))
|
||||
(ssg-in-notify "DIST" text (ssg-in-default w default))
|
||||
)
|
||||
|
||||
;; Schluesselwort ohne Hook (intern, auch von ssg-in-yesno genutzt).
|
||||
(defun ssg-in-keyword-raw (text schluessel default / w)
|
||||
(initget 0 schluessel)
|
||||
(setq w (getkword
|
||||
(ssg-in-prompt
|
||||
(strcat text " [" (vl-string-translate " " "/" schluessel) "]")
|
||||
default)))
|
||||
(ssg-in-default w default)
|
||||
)
|
||||
|
||||
;; Schluesselwort. schluessel im initget-Format, z.B. "Alle Auswahl".
|
||||
;; Rueckgabe: gewaehltes Schluesselwort (volle Schreibweise) oder default.
|
||||
(defun ssg-in-keyword (text schluessel default)
|
||||
(ssg-in-notify "KEYWORD" text (ssg-in-keyword-raw text schluessel default))
|
||||
)
|
||||
|
||||
;; Ja/Nein-Abfrage, Rueckgabe T bei Ja, nil bei Nein (anders als ssg-ques,
|
||||
;; das T fuer die NICHT-vorgegebene Antwort liefert).
|
||||
;; default = T -> Enter bedeutet Ja, nil -> Enter bedeutet Nein.
|
||||
;; Die Schluesselwoerter kommen aus ssg-text "in-yesno-keys" (z.B. "Ja Nein").
|
||||
(defun ssg-in-yesno (text default / schluessel ja nein w)
|
||||
(setq schluessel (ssg-text "in-yesno-keys")
|
||||
ja (ssg-in-first-word schluessel)
|
||||
nein (ssg-in-second-word schluessel))
|
||||
(setq w (ssg-in-keyword-raw text schluessel (if default ja nein)))
|
||||
(ssg-in-notify "YESNO" text (= w ja))
|
||||
)
|
||||
|
||||
(princ)
|
||||
+5
-1
@@ -28,6 +28,7 @@
|
||||
(load (strcat base-path "ssg_dbg.lsp") "ssg_dbg.lsp nicht gefunden")
|
||||
(load (strcat base-path "ssg_dialog.lsp") "ssg_dialog.lsp nicht gefunden")
|
||||
(load (strcat base-path "ssg_layer.lsp") "ssg_layer.lsp nicht gefunden")
|
||||
(load (strcat base-path "ssg_input.lsp") "ssg_input.lsp nicht gefunden")
|
||||
;; Gemeinsame KS-Extraktion + Einfuegeprimitiven - MUSS vor VarioFoerderer
|
||||
;; und Gefaellestrecke geladen werden (beide nutzen sie).
|
||||
(load (strcat base-path "ssg_ks_insert.lsp") "ssg_ks_insert.lsp nicht gefunden")
|
||||
@@ -39,7 +40,10 @@
|
||||
(load (strcat base-path "Tro_Edit.lsp") "Tro_Edit.lsp nicht gefunden")
|
||||
(load (strcat base-path "Connection_Edit.lsp") "Connection_Edit.lsp nicht gefunden")
|
||||
(load (strcat base-path "SSG_LIB_Commands.lsp") "SSG_LIB_Commands.lsp nicht gefunden")
|
||||
(prompt "\nSSG-Bibliotheken geladen: ssg_core, ssg_lang, ssg_dbg, ssg_dialog, ssg_layer, KreiselInsert, VarioFoerderer, Gefaellestrecke, export, OmniModulInsert, SSG_LIB_Commands")
|
||||
;; Werkzeuge: ssg_texttools nutzt ssg_blocktools, beide nutzen ssg_input
|
||||
(load (strcat base-path "ssg_blocktools.lsp") "ssg_blocktools.lsp nicht gefunden")
|
||||
(load (strcat base-path "ssg_texttools.lsp") "ssg_texttools.lsp nicht gefunden")
|
||||
(prompt "\nSSG-Bibliotheken geladen: ssg_core, ssg_lang, ssg_dbg, ssg_dialog, ssg_layer, ssg_input, KreiselInsert, VarioFoerderer, Gefaellestrecke, export, OmniModulInsert, SSG_LIB_Commands, ssg_blocktools, ssg_texttools")
|
||||
(princ)
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,285 @@
|
||||
;; ============================================================
|
||||
;; SSG_TEXTTOOLS.LSP - Text-Werkzeuge
|
||||
;;
|
||||
;; Ursprung: ACADSST/MENU/CHGTEXT.LSP (Suchen/Ersetzen), PARTEXT.LSP
|
||||
;; (Tbpl: parallel beschriften), ALTHOEHE.LSP (Tsz), ALTSTIL.LSP (Ts).
|
||||
;; Neu geschrieben im ssg-Stil (Undo-Gruppe, i18n, ssg-in-*).
|
||||
;;
|
||||
;; Befehle:
|
||||
;; SSG_TEXT_ERSETZEN Zeichenketten in TEXT, MTEXT und Block-
|
||||
;; Attributen suchen/ersetzen (mit Vorschau)
|
||||
;; SSG_TEXT_PARALLEL Text parallel zu Linie/Polylinie/Bogen setzen
|
||||
;; (lesbar ausgerichtet, mit Abstand zur Linie)
|
||||
;; SSG_TEXT_HOEHE Texthoehe von TEXT/MTEXT aendern
|
||||
;; SSG_TEXT_STIL Textstil von TEXT/MTEXT aendern
|
||||
;;
|
||||
;; Arbeitet in der XY-Ebene des Welt-KS (Textrotation = WKS-Winkel).
|
||||
;; Setzt ssg_core.lsp, ssg_lang.lsp, ssg_input.lsp und ssg_blocktools.lsp
|
||||
;; (ssg-bt-wert-neu, ssg-bt-attr-ersetzen-ent) voraus.
|
||||
;; ============================================================
|
||||
|
||||
(vl-load-com)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; REINE HILFSFUNKTIONEN (in test_unit getestet)
|
||||
;; ------------------------------------------------------------
|
||||
|
||||
;; Winkel (Bogenmass) so drehen, dass ein Text lesbar bleibt: Winkel im
|
||||
;; Bereich (90 Grad, 270 Grad] werden um 180 Grad gedreht. Ergebnis in
|
||||
;; [0, 2*pi).
|
||||
(defun ssg-tt-lesbarer-winkel (a)
|
||||
(setq a (rem a (* 2.0 pi)))
|
||||
(if (< a 0.0) (setq a (+ a (* 2.0 pi))))
|
||||
(if (and (> a (+ (/ pi 2.0) 1e-9))
|
||||
(<= a (+ (* 1.5 pi) 1e-9)))
|
||||
(setq a (- a pi))
|
||||
)
|
||||
(if (< a 0.0) (setq a (+ a (* 2.0 pi))))
|
||||
a
|
||||
)
|
||||
|
||||
;; Punkt um abstand in Richtung winkel verschieben (2D, Z bleibt erhalten)
|
||||
(defun ssg-tt-versetzt (p winkel abstand)
|
||||
(list (+ (car p) (* abstand (cos winkel)))
|
||||
(+ (cadr p) (* abstand (sin winkel)))
|
||||
(if (caddr p) (caddr p) 0.0))
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; AUSWAHL
|
||||
;; ------------------------------------------------------------
|
||||
|
||||
;; Auswahlsatz der angegebenen Typen holen (z.B. "TEXT,MTEXT,INSERT").
|
||||
;; alle-p = T -> alle im aktuellen Layout, nil -> Benutzerwahl
|
||||
(defun ssg-tt-ss-holen (alle-p typen)
|
||||
(if alle-p
|
||||
(ssget "_X" (list (cons 0 typen) (cons 410 (getvar "CTAB"))))
|
||||
(ssget (list (cons 0 typen)))
|
||||
)
|
||||
)
|
||||
|
||||
;; Auswahlsatz -> Liste von Entity-Namen mit Typ-Filter ("TEXT" "MTEXT" ...)
|
||||
(defun ssg-tt-ss-liste (ss typen / i ent res)
|
||||
(if ss
|
||||
(progn
|
||||
(setq i 0)
|
||||
(while (setq ent (ssname ss i))
|
||||
(if (member (cdr (assoc 0 (entget ent))) typen)
|
||||
(setq res (cons ent res))
|
||||
)
|
||||
(setq i (1+ i))
|
||||
)
|
||||
)
|
||||
)
|
||||
(reverse res)
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; SUCHEN / ERSETZEN
|
||||
;; ------------------------------------------------------------
|
||||
|
||||
;; TEXT/MTEXT-Inhalte ersetzen (oder nur zaehlen). Rueckgabe: Anzahl Texte.
|
||||
(defun ssg-tt-text-ersetzen-liste (ents suche ersatz teil-p probe-p
|
||||
/ n obj alt neu)
|
||||
(setq n 0)
|
||||
(foreach ent ents
|
||||
(setq obj (vlax-ename->vla-object ent)
|
||||
alt (vla-get-textstring obj)
|
||||
neu (ssg-bt-wert-neu alt suche ersatz teil-p))
|
||||
(if neu
|
||||
(if probe-p
|
||||
(setq n (1+ n))
|
||||
(if (not (vl-catch-all-error-p
|
||||
(vl-catch-all-apply 'vla-put-textstring (list obj neu))))
|
||||
(setq n (1+ n))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
n
|
||||
)
|
||||
|
||||
;; Texte + Attribute in einem Auswahlsatz ersetzen/zaehlen.
|
||||
;; Rueckgabe: (anzahl-texte . anzahl-attribute)
|
||||
(defun ssg-tt-ersetzen-ss (ss suche ersatz teil-p probe-p)
|
||||
(cons
|
||||
(ssg-tt-text-ersetzen-liste
|
||||
(ssg-tt-ss-liste ss '("TEXT" "MTEXT")) suche ersatz teil-p probe-p)
|
||||
(ssg-bt-attr-ersetzen-liste
|
||||
(ssg-tt-ss-liste ss '("INSERT")) "*" suche ersatz teil-p probe-p)
|
||||
)
|
||||
)
|
||||
|
||||
(defun c:SSG_TEXT_ERSETZEN ( / k-bereich k-modus alle-p ss suche ersatz modus teil-p z)
|
||||
(setq k-bereich (ssg-text "in-keys-bereich")
|
||||
k-modus (ssg-text "in-keys-modus")
|
||||
alle-p (= (ssg-in-keyword (ssg-text "tt-bereich") k-bereich
|
||||
(ssg-in-first-word k-bereich))
|
||||
(ssg-in-first-word k-bereich)))
|
||||
(if (not alle-p) (prompt (ssg-text "tt-auswahl")))
|
||||
(setq ss (ssg-tt-ss-holen alle-p "TEXT,MTEXT,INSERT"))
|
||||
(if (null ss)
|
||||
(prompt (ssg-text "tt-keine-objekte"))
|
||||
(progn
|
||||
(setq suche (ssg-in-string (ssg-text "tt-suche") nil))
|
||||
(if (or (null suche) (= suche ""))
|
||||
(prompt (ssg-text "tt-abgebrochen"))
|
||||
(progn
|
||||
(setq ersatz (ssg-in-string (ssg-text "tt-ersatz") "")
|
||||
modus (ssg-in-keyword (ssg-text "tt-modus") k-modus
|
||||
(ssg-in-first-word k-modus))
|
||||
teil-p (= modus (ssg-in-first-word k-modus)))
|
||||
(setq z (ssg-tt-ersetzen-ss ss suche ersatz teil-p T))
|
||||
(cond
|
||||
((= 0 (+ (car z) (cdr z))) (prompt (ssg-text "tt-nichts")))
|
||||
((ssg-in-yesno (ssg-textf "tt-frage" (list (car z) (cdr z))) T)
|
||||
(ssg-start (ssg-text "tt-ersetzen-titel") nil)
|
||||
(setq z (ssg-tt-ersetzen-ss ss suche ersatz teil-p nil))
|
||||
(ssg-end)
|
||||
(prompt (ssg-textf "tt-ergebnis" (list (car z) (cdr z)))))
|
||||
(t (prompt (ssg-text "tt-abgebrochen")))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(princ)
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; PARALLEL BESCHRIFTEN
|
||||
;; ------------------------------------------------------------
|
||||
|
||||
;; Winkel der Kurve (Linie, Polylinie, Bogen, ...) am Punkt pt (WKS).
|
||||
;; Rueckgabe: Winkel in Bogenmass oder nil, wenn nicht ermittelbar.
|
||||
(defun ssg-tt-kurven-winkel (ent pt / obj cp param deriv)
|
||||
(setq obj (vlax-ename->vla-object ent))
|
||||
(setq cp (vl-catch-all-apply 'vlax-curve-getclosestpointto (list obj pt)))
|
||||
(if (or (vl-catch-all-error-p cp) (null cp))
|
||||
nil
|
||||
(progn
|
||||
(setq param (vl-catch-all-apply 'vlax-curve-getparamatpoint (list obj cp)))
|
||||
(if (or (vl-catch-all-error-p param) (null param))
|
||||
nil
|
||||
(progn
|
||||
(setq deriv (vl-catch-all-apply 'vlax-curve-getfirstderiv (list obj param)))
|
||||
(if (or (vl-catch-all-error-p deriv) (null deriv))
|
||||
nil
|
||||
(list (atan (cadr deriv) (car deriv)) cp)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; TEXT erzeugen (unten mittig, Gruppe 73 = 1 damit Gruppe 11 gilt)
|
||||
(defun ssg-tt-text-machen (p hoehe string winkel)
|
||||
(entmake (list '(0 . "TEXT")
|
||||
(cons 8 (getvar "CLAYER"))
|
||||
(cons 7 (getvar "TEXTSTYLE"))
|
||||
(cons 10 p)
|
||||
(cons 11 p)
|
||||
(cons 40 hoehe)
|
||||
(cons 1 string)
|
||||
(cons 50 winkel)
|
||||
(cons 72 1)
|
||||
(cons 73 1)))
|
||||
)
|
||||
|
||||
(defun c:SSG_TEXT_PARALLEL ( / sel info a ar p text)
|
||||
(ssg-start (ssg-text "tt-parallel-titel") nil)
|
||||
(if (or (null *ssg-tt-hoehe*) (<= *ssg-tt-hoehe* 0.0))
|
||||
(setq *ssg-tt-hoehe* (if (> (getvar "TEXTSIZE") 0.0) (getvar "TEXTSIZE") 2.5))
|
||||
)
|
||||
(setq *ssg-tt-hoehe* (ssg-in-real (ssg-text "tt-hoehe") *ssg-tt-hoehe*))
|
||||
(if (null *ssg-tt-abstand*)
|
||||
(setq *ssg-tt-abstand* (* 0.5 *ssg-tt-hoehe*))
|
||||
)
|
||||
(setq *ssg-tt-abstand* (ssg-in-real (ssg-text "tt-abstand") *ssg-tt-abstand*))
|
||||
(while (setq sel (entsel (ssg-text "tt-parallel-waehlen")))
|
||||
(setq info (ssg-tt-kurven-winkel (car sel) (trans (cadr sel) 1 0)))
|
||||
(if (null info)
|
||||
(prompt (ssg-text "tt-parallel-keine-kurve"))
|
||||
(progn
|
||||
(setq a (car info)
|
||||
ar (ssg-tt-lesbarer-winkel a)
|
||||
p (ssg-tt-versetzt (cadr info) (+ ar (/ pi 2.0)) *ssg-tt-abstand*)
|
||||
text (ssg-in-string (ssg-text "tt-text") *ssg-tt-text*))
|
||||
(if (and text (/= text ""))
|
||||
(progn
|
||||
(setq *ssg-tt-text* text)
|
||||
(if (not (ssg-tt-text-machen p *ssg-tt-hoehe* text ar))
|
||||
(prompt (ssg-text "tt-parallel-fehler"))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(ssg-end)
|
||||
(princ)
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; HOEHE / STIL AENDERN
|
||||
;; ------------------------------------------------------------
|
||||
|
||||
(defun c:SSG_TEXT_HOEHE ( / ents hoehe n)
|
||||
(prompt (ssg-text "tt-auswahl"))
|
||||
(setq ents (ssg-tt-ss-liste (ssget '((0 . "TEXT,MTEXT"))) '("TEXT" "MTEXT")))
|
||||
(if (null ents)
|
||||
(prompt (ssg-text "tt-keine-objekte"))
|
||||
(progn
|
||||
(setq hoehe (ssg-in-real (ssg-text "tt-hoehe")
|
||||
(if (> (getvar "TEXTSIZE") 0.0) (getvar "TEXTSIZE") nil)))
|
||||
(if (or (null hoehe) (<= hoehe 0.0))
|
||||
(prompt (ssg-text "tt-abgebrochen"))
|
||||
(progn
|
||||
(ssg-start (ssg-text "tt-hoehe-titel") nil)
|
||||
(setq n 0)
|
||||
(foreach ent ents
|
||||
(if (not (vl-catch-all-error-p
|
||||
(vl-catch-all-apply 'vla-put-height
|
||||
(list (vlax-ename->vla-object ent) hoehe))))
|
||||
(setq n (1+ n))
|
||||
)
|
||||
)
|
||||
(ssg-end)
|
||||
(prompt (ssg-textf "tt-geaendert" (list n)))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(princ)
|
||||
)
|
||||
|
||||
(defun c:SSG_TEXT_STIL ( / ents stil n)
|
||||
(prompt (ssg-text "tt-auswahl"))
|
||||
(setq ents (ssg-tt-ss-liste (ssget '((0 . "TEXT,MTEXT"))) '("TEXT" "MTEXT")))
|
||||
(if (null ents)
|
||||
(prompt (ssg-text "tt-keine-objekte"))
|
||||
(progn
|
||||
(setq stil (ssg-in-string (ssg-text "tt-stil") (getvar "TEXTSTYLE")))
|
||||
(cond
|
||||
((or (null stil) (null (tblsearch "STYLE" stil)))
|
||||
(prompt (ssg-textf "tt-stil-fehlt" (list (if stil stil "")))))
|
||||
(t
|
||||
(ssg-start (ssg-text "tt-stil-titel") nil)
|
||||
(setq n 0)
|
||||
(foreach ent ents
|
||||
(if (not (vl-catch-all-error-p
|
||||
(vl-catch-all-apply 'vla-put-stylename
|
||||
(list (vlax-ename->vla-object ent) stil))))
|
||||
(setq n (1+ n))
|
||||
)
|
||||
)
|
||||
(ssg-end)
|
||||
(prompt (ssg-textf "tt-geaendert" (list n))))
|
||||
)
|
||||
)
|
||||
)
|
||||
(princ)
|
||||
)
|
||||
|
||||
(princ)
|
||||
Reference in New Issue
Block a user