Files
dxfmakros/Lisp/ssg_blocktools.lsp
T
m.stangl fcb4444ee1 [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>
2026-10-07 11:40:11 +02:00

312 lines
10 KiB
Common Lisp

;; ============================================================
;; 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)