Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
144 lines
6.4 KiB
Python
144 lines
6.4 KiB
Python
"""Dimension, text and multileader styles (track E, group S).
|
|
|
|
``AutoCADBackend`` composes every contract in this package, so importing
|
|
``backends.base.AutoCADBackend`` is unchanged for callers.
|
|
|
|
Names are matched case-insensitively — AutoCAD's rule for every symbol
|
|
table — and reported in the table's own spelling. Every refusal is raised
|
|
before a table is touched: ``ValueError`` naming the key (a missing style, a
|
|
clash, a variable outside ``engineering.standards.dimstyles.DIM_VARIABLE_RANGES``),
|
|
``TypeError`` for a wrong type.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from abc import ABC, abstractmethod
|
|
|
|
from backends.capability import capability
|
|
|
|
|
|
class StylesContract(ABC):
|
|
@abstractmethod
|
|
async def dimstyle_list(self) -> list[dict]:
|
|
"""Every DIMSTYLE entry: ``[{name, current, values, values_available}]``.
|
|
|
|
``values`` holds the seventeen preset variables
|
|
(``engineering.standards.dimstyles.PRESET_VARIABLES``) with ``DIMDSEP``
|
|
as the character. Headless every row carries them (the DXF's stored
|
|
value, else the schema default AutoCAD applies to an omitted code).
|
|
On the live engine ActiveX has no per-style getters — ``AcadDimStyle``
|
|
exposes ``Name`` and ``CopyFrom`` only — so ``values`` is read for the
|
|
*current* style and the other rows carry ``values: None`` with
|
|
``values_available: False`` rather than cycling the active style
|
|
behind the operator's back.
|
|
"""
|
|
...
|
|
|
|
@abstractmethod
|
|
async def dimstyle_create(self, name: str, values: dict, set_current: bool = False) -> dict:
|
|
"""Create a dimension style from a fully resolved ``values`` dict
|
|
(``engineering.standards.dimstyles.resolve_dimstyle(preset, overrides)``).
|
|
|
|
Returns ``{ok, name, values, written, current, textstyle_created}``.
|
|
``DIMTXSTY`` must name a text style that exists or a bundled preset
|
|
(ISOCP / ISOCPEUR / ARIAL / ROMANS), which is created first and
|
|
reported in ``textstyle_created``; anything else is refused by name.
|
|
A name clash is refused (``dimstyle_modify`` changes an existing
|
|
style). With ``set_current`` the style becomes ``$DIMSTYLE`` *and* its
|
|
values become the current ``DIM*`` settings — what a live seat does —
|
|
so the next dimension carries them on both engines.
|
|
"""
|
|
...
|
|
|
|
@abstractmethod
|
|
async def dimstyle_modify(self, name: str, values: dict) -> dict:
|
|
"""Change variables on an existing style.
|
|
|
|
Returns ``{ok, name, changed: {VAR: [old, new]}, dimensions_using_style,
|
|
rerender_required}``. ``changed`` names only the variables that moved
|
|
(the ``hatch_edit`` rule: re-setting a value to itself is not a
|
|
change). Dimensions already drawn with the style are listed by handle;
|
|
``rerender_required`` is ``True`` headlessly when any exist and
|
|
something changed, because a headless DIMENSION carries its rendered
|
|
block and shows the old style until it is redrawn — AutoCAD re-renders
|
|
on the next regen, so the live engine reports ``False``. Modifying the
|
|
current style also updates the ``DIM*`` current settings.
|
|
"""
|
|
...
|
|
|
|
@abstractmethod
|
|
async def dimstyle_set_current(self, name: str) -> dict:
|
|
"""Make ``name`` the current dimension style.
|
|
|
|
Returns ``{ok, current, previous, changed}``. Sets ``$DIMSTYLE`` and
|
|
loads the style's stored variables into the current ``DIM*`` settings
|
|
(AutoCAD's ``-DIMSTYLE Restore``; on the live engine unsaved overrides
|
|
of the previous style are discarded, which is AutoCAD's own rule).
|
|
The dimension tools then create dimensions with it; the per-dimension
|
|
override path (tolerances, fits, text override) is unchanged.
|
|
"""
|
|
...
|
|
|
|
@abstractmethod
|
|
async def textstyle_list(self) -> list[dict]:
|
|
"""``[{name, font, height, width_factor, oblique_deg, current}]``."""
|
|
...
|
|
|
|
@abstractmethod
|
|
async def textstyle_create(
|
|
self,
|
|
name: str,
|
|
font: str,
|
|
height: float = 0.0,
|
|
width_factor: float = 1.0,
|
|
oblique_deg: float = 0.0,
|
|
set_current: bool = False,
|
|
) -> dict:
|
|
"""Create a text style. Returns ``{ok, name, font, font_resolved, current}``.
|
|
|
|
``font`` is a preset (``ISOCP`` / ``isocp.shx`` / ``isocp``, any case)
|
|
or any file name. A file that is neither a preset nor found on the
|
|
engine's font path is *written* and reported ``font_resolved: False``
|
|
— a DXF stores only the name and AutoCAD substitutes at open — never
|
|
refused. Refuses a clash, ``width_factor <= 0``, ``height < 0``, an
|
|
oblique angle outside ±85°, an empty font.
|
|
"""
|
|
...
|
|
|
|
@abstractmethod
|
|
async def textstyle_set_current(self, name: str) -> dict:
|
|
"""``$TEXTSTYLE``. Returns ``{ok, current, previous, changed}``; new
|
|
TEXT/MTEXT then carry the style on both engines."""
|
|
...
|
|
|
|
@abstractmethod
|
|
async def mleaderstyle_list(self) -> list[dict]:
|
|
"""``[{name, arrow_size, landing_gap, text_style, text_height, values_available}]``.
|
|
|
|
Headless the values are read from the MLEADERSTYLE object (schema
|
|
defaults for an unset field). ActiveX exposes no MLeaderStyle object,
|
|
so the live engine reads the *names* from the ``ACAD_MLEADERSTYLE``
|
|
dictionary and reports the four values ``None`` with
|
|
``values_available: False``.
|
|
"""
|
|
...
|
|
|
|
# B027 (empty method, no @abstractmethod) is what this pattern looks like
|
|
# from the outside: the decorator replaces the `...` body with the refusing
|
|
# default, so the source really is empty on purpose.
|
|
@capability( # noqa: B027
|
|
"mleaderstyle",
|
|
reason=(
|
|
"ActiveX exposes no MLeaderStyle collection; use leader_create_mleader's "
|
|
"per-leader parameters (arrow size, landing, text height) or the headless "
|
|
"backend (AUTOCAD_MCP_BACKEND=ezdxf)"
|
|
),
|
|
)
|
|
async def mleaderstyle_create(self, name: str, values: dict) -> dict:
|
|
"""Create a multileader style from a resolved ``values`` dict
|
|
(``engineering.standards.mleaderstyles.resolve_mleaderstyle``).
|
|
ezdxf only. Returns ``{ok, name, values, textstyle_created}``; the
|
|
text style follows the ``dimstyle_create`` rule (exists or preset,
|
|
else refused by name); a clash is refused."""
|
|
...
|