forked from 1b-agent/opencadstudio-upstream
feat(python): block definitions (doc.blocks)
TableOperation gains BlockCreate (copy entities into a definition shifted by the base point, optionally erasing originals), BlockModify, BlockRename (inserts follow) and BlockDelete (refused while referenced; removes members, markers and orphaned draw-order tables). Real-IPC audit with DWG/DXF persistence and undo, IPC and Python unit tests, docs; the DXF loss of the block description is pinned by a canary. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
1 parent
aaea15e4ef
commit
8d20d280fe
9 files changed
+612
No files matched your search
@@ -396,12 +396,77 @@ class _DimStyles(_Styles):
|
||||
return self[name]
|
||||
|
||||
|
||||
class _Blocks:
|
||||
"""`ocs.active_document.blocks`: user block definitions (layout and
|
||||
anonymous blocks are not listed). Every change is validated by the host, is
|
||||
one undo step, and a refusal raises `RuntimeError` without changing the
|
||||
drawing. Place a block with `create_entity("Insert", block_name=...)`."""
|
||||
|
||||
def _records(self):
|
||||
return ocs.block_records()
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._records())
|
||||
|
||||
def __len__(self):
|
||||
return len(self._records())
|
||||
|
||||
def __contains__(self, name):
|
||||
wanted = str(name).strip().upper()
|
||||
return any(r["name"].upper() == wanted for r in self._records())
|
||||
|
||||
def __getitem__(self, name):
|
||||
wanted = str(name).strip().upper()
|
||||
for record in self._records():
|
||||
if record["name"].upper() == wanted:
|
||||
return record
|
||||
raise KeyError(name)
|
||||
|
||||
def get(self, name, default=None):
|
||||
try:
|
||||
return self[name]
|
||||
except KeyError:
|
||||
return default
|
||||
|
||||
def names(self):
|
||||
return [r["name"] for r in self._records()]
|
||||
|
||||
def create(self, name, entities, base_point=(0, 0, 0), erase_originals=False, description=None):
|
||||
"""Define a block from existing model/paper-space entities (descriptors
|
||||
or handles). They are copied into the definition shifted by
|
||||
`-base_point`; `erase_originals=True` removes them from the drawing, as
|
||||
the BLOCK command does. No insert is placed."""
|
||||
handles = [e.handle if isinstance(e, _Entity) else int(e) for e in entities]
|
||||
options = {"entities": handles, "base_point": [float(v) for v in base_point],
|
||||
"erase_originals": bool(erase_originals)}
|
||||
if description is not None:
|
||||
options["description"] = str(description)
|
||||
ocs.block_operation("create", str(name), options)
|
||||
return self[name]
|
||||
|
||||
def modify(self, name, description=None, explodable=None, scale_uniformly=None):
|
||||
options = {k: v for k, v in (("description", description), ("explodable", explodable),
|
||||
("scale_uniformly", scale_uniformly)) if v is not None}
|
||||
ocs.block_operation("modify", str(name), options)
|
||||
return self[name]
|
||||
|
||||
def rename(self, name, new_name):
|
||||
"""Rename a block; every insert of it follows."""
|
||||
ocs.block_operation("rename", str(name), {"to": str(new_name)})
|
||||
return self[new_name]
|
||||
|
||||
def delete(self, name):
|
||||
"""Delete a block that no insert, style or leader still uses."""
|
||||
ocs.block_operation("delete", str(name), None)
|
||||
|
||||
|
||||
class _Document:
|
||||
def __init__(self):
|
||||
self._pending = None
|
||||
self.layers = _Layers()
|
||||
self.text_styles = _TextStyles()
|
||||
self.dim_styles = _DimStyles()
|
||||
self.blocks = _Blocks()
|
||||
self.entities = _Entities(self)
|
||||
self.solids = _Solids(self)
|
||||
|
||||
|
||||
Reference in new issue
Block a user