Commit Graph
77 Commits
Author SHA1 Message Date
Marco Arnulfo c68420221c New metric drawings get metric Standard multileader and table styles (fixes #1171) (#1195) 2026-10-19 02:30:51 -04:00
56d73ceb21 Dynamic blocks: show a distance's grip only at an end an action follows, and the grips of parameters a visibility state lists (#1090)
* Dynamic blocks: a distance's grip shows only at an end an action follows

A linear parameter's grip at an end no action is attached to moves nothing,
and AutoCAD doesn't show it on the reference: a stretch that follows only the
end's change (EndXDelta, EndYDelta) leaves the base without a grip, and the
other way round. A connection to the distance itself follows both ends, as
does a distance measured from its midpoint; a parameter no action is attached
to keeps the grips the block gives it. (A block saved with one grip has no
base grip at all, which was already honoured.)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic blocks: a visibility state that lists a parameter shows its grips

AutoCAD shows a parameter's grips in a visibility state that lists the
parameter, though the state doesn't list the grips themselves (a label block's
Label state lists Position1 and Distance2 but not their grips, and AutoCAD
shows the square and the arrow). A grip now shows when the state lists it or
its parameter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Cody Vogt <18035288+codyvogt@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 02:29:13 -04:00
aldozarandClaude Opus 5.5 691bdbe0b8 Layouts in millimetres plot in millimetres whatever MEASUREMENT says (#1058) (#1085)
Paper-space units followed the drawing's MEASUREMENT only, so a layout
whose page setup is in millimetres (plot paper units 1), common in
drawings from AutoCAD with MEASUREMENT 0, was taken as inches: its PDF
drew everything 25.4 times too large, off the page.

PageSetup gains `paper_mm`, read from LAYOUT group 72 = 1; 72 = 0 still
leaves the units to MEASUREMENT, since earlier CADCraft versions wrote 0
for every layout. The layout's sheet, its PDF/raster plots, PREVIEW and
the pens of what its viewports show use the layout's units, and the
writer stores 72 = 1 for layouts in millimetres (it wrote 0 always).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 02:29:03 -04:00
26179f7428 Draw object transparency on screen, in exports and in plots (#764)
* Draw object transparency on screen, in exports and in plots

Transparency was read and saved (entity group 440, layer xdata, ByLayer and
ByBlock) but never drawn. Display lists now carry each object's effective
transparency (its own, its layer's, or the block reference's), and:

- the canvas (GPU and CPU paths), ui.render and PNG/SVG exports blend it;
  TRANSPARENCYDISPLAY turns it off on screen and is now on by default, as in
  AutoCAD (initial value 1);
- plots draw it only when "Plot transparency" is on: a page setup option
  (PAGESETUP `plotTransparency`, a checkbox in the Page Setup Manager and the
  Plot dialog), overridable per plot, with PLOTTRANSPARENCYOVERRIDE (0 never,
  1 the setting, 2 always). PDF gets /ExtGState alpha, PNG plots blend, SVG
  uses opacity. Plots without it are byte-identical to before.

The public DXF Reference has no plot layout flag for plot transparency, so
the option is kept in the session and in JSON, not in DXF/DWG.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Transparency fixes: attributes, PDF overlaps, drag previews

- Attributes draw with their own transparency (their definition's, layer 0
  meaning the reference's layer, ByBlock the reference's) instead of the
  block reference's.
- PDF plots stroke overlapping transparent objects one by one, so they build
  up where they cross as in PNG plots; opaque output is unchanged.
- Drag and rubber-band previews follow TRANSPARENCYDISPLAY.
- Effective transparency is worked out only when it is drawn, reusing the
  layer the property lookup already found.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Transparency: one PDF stroke per transparent primitive; opaque rebuilt previews

- PDF plots never batch two transparent primitives into one path. Block and
  viewport contents share their reference's handle, so the per-object flush
  missed them; each primitive now blends on its own, as in PNG plots and on
  screen. Opaque output is unchanged.
- Previews the session rebuilds with the current properties (rubber bands,
  copies of objects) are drawn opaque again: they carry CLAYER's
  transparency, not the objects'. The GPU drag of the objects themselves
  keeps following TRANSPARENCYDISPLAY.
- Tests for attributes on a transparent reference layer, attributes without a
  definition, and the drag cache across the TRANSPARENCYDISPLAY toggle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Selection like AutoCAD: colour highlight and the Options Selection tab

Selecting or hovering an object outlined each filled primitive (TrueType
glyphs, dimension and leader arrowheads, solid hatches, wide polylines)
by the rectangle around its triangles, and dashed everything else. A
selected dimension's text became a row of dashed boxes, one per glyph,
and its closed arrowheads small rectangles.

Selected objects are now redrawn in the selection colour: lines solid,
fills filled half see-through (so the lines and text on a highlighted
hatch stay visible), and the whole object reads as selected, text and
arrowheads included. A wipeout is always outlined, since filling it would
hide the drawing under it.

The Options dialog's Selection tab is laid out as AutoCAD's, with the
settings CADCraft can act on, each one AutoCAD's variable, kept in the
user profile:

- Selection modes: noun/verb selection (PICKFIRST), Shift to add
  (PICKADD), Object grouping (PICKSTYLE bit 1, now saved in the profile).
- Selection effect color (selectionColor, an interface preference; null
  is the theme's).
- Grips: Show grips (GRIPS) and the object selection limit for display of
  grips (GRIPOBJLIMIT, 100; 0 no limit): grips are neither drawn nor
  picked beyond it.
- Selection preview (SELECTIONPREVIEW): the object under the cursor is
  highlighted when a command is active (2) and when none is (1).
- Visual Effect Settings: the selection area effect (SELECTIONAREA,
  WINDOWAREACOLOR 150, CROSSINGAREACOLOR 100, SELECTIONAREAOPACITY 25)
  and the Selection Preview Filter (PREVIEWFILTER 3: 1 objects on locked
  layers, 2 xrefs, 4 tables, 8 multiline text, 16 hatches, 32 groups).

As in AutoCAD these are typed, not on the dialog: HIGHLIGHT (0 shows only
the grips of selected objects; not saved, so every session starts
highlighted), SELECTIONEFFECT (1 the selection colour, 0 dashed lines with
fills outlined along their real boundary) and PREVIEWEFFECT (the preview
dashed 0, thicker 1 or both 2).

Left for later, as CADCraft lacks what they control: lasso, grip tips and
menus, group grips, grips within blocks, associative hatch selection,
command and property preview, PICKDRAG, PICKAUTO and PROPOBJLIMIT.

DisplayList::fill_outlines returns the boundary of the region a filled
primitive covers as closed polylines (edges only one triangle has; the
slab filler's horizontal cuts, which need not line up between trapezoids,
are split at every x on their line and kept where an odd number cover
them), falling back to the bounding box over 600,000 vertices. The GPU
and CPU highlight paths and the drawing comparison overlay share the same
looks.

The new labels have Ukrainian rows (the required catalog); other
languages fall back to English.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: EP995LAB <293597958+EP995LAB@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Cody Vogt <18035288+codyvogt@users.noreply.github.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-13 06:12:48 -04:00
62fb5ae79a Attributes keep Verify, Preset and Lock position (stacked on #854) (#876)
* Multiline attributes: read, draw and save their text

A multiline attribute (DXF attribute type 2, or 4 for a definition) has its
text as embedded MTEXT after its own groups (`101 Embedded Object`); its own
group 1 is empty. CADCraft read only the own groups, so the attribute drew
nothing, and a save wrote it back empty: its text was lost.

- `Attrib::multiline` keeps the multiline text; `text.value` holds its plain
  text, which ATTEDIT and the other value editors change; an edited value
  replaces the contents (`Attrib::multiline_text`).
- DXF read: ATTRIB and ATTDEF split at the marker; the MTEXT parsing is
  shared with MTEXT entities (`mtext_from`).
- Drawn as multiline text; ZOOM Extents counts it.
- DXF write (2007 and later; earlier versions get one line): attribute type,
  alignment point and the embedded MTEXT, only what differs from unrotated
  text, as AutoCAD writes it.
- INSERT and ATTSYNC give references the definition's multiline text placed
  with them; MOVE/ROTATE/SCALE, Properties rotation and scale, annotative
  scaling and FLATTEN carry it.
- Tests: synthetic multiline ATTDEF and ATTRIB (read, drawn, saved, edited,
  pre-2007 save, damaged embedded groups); engine INSERT, MOVE, ATTEDIT and
  ATTSYNC.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Multiline attributes: read MTEXT direction from its own groups (#667, as #834 does)

#834 moves these lines' fix into the MTEXT reader; the same fix in the shared
mtext_from keeps the two compatible.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Attributes keep Verify, Preset and Lock position

ATTDEF/ATTRIB flags 4 (verify) and 8 (preset) and Lock position (group 280
after the tag, DXF 2007 and later) were dropped on save. Without Lock
position AutoCAD lets an attribute be dragged out of its reference, and its
dynamic block actions no longer carry it. A reference's attributes take Lock
position from their definitions, as AutoCAD saves them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Cody Vogt <18035288+codyvogt@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-13 05:56:05 -04:00
3199de4951 Multiline attributes: read, draw and save their text (they were lost on save) (#854)
* Multiline attributes: read, draw and save their text

A multiline attribute (DXF attribute type 2, or 4 for a definition) has its
text as embedded MTEXT after its own groups (`101 Embedded Object`); its own
group 1 is empty. CADCraft read only the own groups, so the attribute drew
nothing, and a save wrote it back empty: its text was lost.

- `Attrib::multiline` keeps the multiline text; `text.value` holds its plain
  text, which ATTEDIT and the other value editors change; an edited value
  replaces the contents (`Attrib::multiline_text`).
- DXF read: ATTRIB and ATTDEF split at the marker; the MTEXT parsing is
  shared with MTEXT entities (`mtext_from`).
- Drawn as multiline text; ZOOM Extents counts it.
- DXF write (2007 and later; earlier versions get one line): attribute type,
  alignment point and the embedded MTEXT, only what differs from unrotated
  text, as AutoCAD writes it.
- INSERT and ATTSYNC give references the definition's multiline text placed
  with them; MOVE/ROTATE/SCALE, Properties rotation and scale, annotative
  scaling and FLATTEN carry it.
- Tests: synthetic multiline ATTDEF and ATTRIB (read, drawn, saved, edited,
  pre-2007 save, damaged embedded groups); engine INSERT, MOVE, ATTEDIT and
  ATTSYNC.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Multiline attributes: read MTEXT direction from its own groups (#667, as #834 does)

#834 moves these lines' fix into the MTEXT reader; the same fix in the shared
mtext_from keeps the two compatible.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Cody Vogt <18035288+codyvogt@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-13 05:54:25 -04:00
48352f2baf Dynamic block grips: show and drag a dynamic reference's grips (stacked on #878) (#883)
* Dynamic blocks: read parameters and actions from AutoCAD files

A dynamic block's evaluation graph (kept as foreign data since #528) is read
into a typed model, `cadcraft_doc::dynblock`, without changing the kept
data: parameters (linear with value sets, point, visibility states,
lookup, base point; polar, XY, rotation, alignment and flip by geometry)
and actions (stretch with its frame and moved vertices, lookup tables;
move, scale, rotate, flip, array, polar stretch by kind), each with its
graph id and the parameters it follows.

- `blocks.dynamic {name}` returns the model as JSON (handles as hex);
  `blocks.list` marks dynamic blocks.
- Counts and values come from the file: capped by the groups present,
  non-finite numbers and missing members skipped.
- Tests: a synthetic DOOR block (visibility, linear list, stretch, lookup),
  its survival through a save, damaged data, and the engine commands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic block references: their values and custom properties

A dynamic block reference's extension dictionary says which dynamic block it
shows (AcDbBlockRepresentation ▸ AcDbRepData) and the values it was given
(AppDataCache ▸ ACAD_ENHANCEDBLOCKDATA, one XRECORD per parameter graph id).
`dynblock::reference` reads them; a reference to the dynamic block itself
has the block's values.

- `dynblock::custom_properties`: the Properties palette's Custom section, in
  parameter order, only parameters shown in Properties: visibility state,
  lookup value worked out from the lookup tables (their "no match" name, e.g.
  Custom, when the inputs match no row), distances and point positions in
  drawing units (block units × the reference's scale), with the choices of
  each (states, lookup values, a distance's list).
- Properties: a dynamic block reference shows its dynamic block's name
  instead of its anonymous block's, and a read-only Custom section.
- `blocks.reference {handle}` returns the definition, values and properties.
- Tests: synthetic references (own values, an anonymous block scaled 2, a
  width no lookup row has), survival through a save, the engine command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic block references: change the visibility state

Choosing a visibility state (or a lookup value whose tables set only
visibility states) in Properties ▸ Custom, or `blocks.reference.set
{handle, name, value}`, changes a dynamic block reference as AutoCAD does:

- The reference gets a new anonymous block: its current one with the
  state's objects shown and the parameter's other objects hidden (matched
  to the dynamic block's objects by their AcDbBlockRepETag element tags).
  The old anonymous block goes when nothing else uses it.
- AutoCAD's link data is written: the new block's record carries
  AcDbBlockRepBTag (the dynamic block's record), copied objects keep their
  element tags, and the reference's AcDbBlockRepresentation data records the
  value (an existing value record is updated; a new one copies another
  reference's record for the same parameter when there is one).
- An attribute whose definition the state hides is written hidden (60).
- Changes CADCraft can't make yet (distances, positions, lookups that set
  them) are refused with a message and change nothing; Properties shows
  only what can change as a dropdown (`CustomProperty::editable`).
- Tests: the synthetic DOOR references (own values and an anonymous block),
  survival through a save, refusals, and the engine command with undo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic block references: distances, positions, stretch and move actions, lookup chaining

Linear distances (snapped to their value sets) and point positions can be
changed; the stretch and move actions that follow them run (listed vertices
or whole objects, multiplier and angle offset), parameters in an action's
selection are carried along, associative hatches refill from their
stretched outlines and the reference's attributes move with their
definitions. Lookup tables run both ways (a changed input gives its table's
lookup value, which sets the other tables' inputs). Connections are read in
either group order. Checked against AutoCAD's own references (*U10, *U12).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic block references: record changes in the history as AutoCAD does; full value data for new references

A changed reference's ACAD_ENHANCEDBLOCKHISTORY says what was done to it: a
visibility state or lookup value by property name, a distance or position as
the drag of its grips (GRIPLOC, how far each grip is from where the dynamic
block has it). A reference that had no data gets a record for everything
other references of the same dynamic block have, with its own values.
Templates come only from references of the same dynamic block; anonymous
copies have no units; boundary reactors follow the copies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic block history: record only the grips a change moves

AutoCAD's history holds the user's own drags; a grip that only moved with
another parameter (a stretch carrying it) gets no entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic block history: a distance by name, as typed in Properties

AutoCAD records a distance typed in Properties as the parameter's name and
value in block units (1071 id, 300 Distance2, 40 40.0), replacing drags of
its grips; positions stay grip drags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* DWG: dynamic block lookup parameters keep their name and lookup action

AutoCAD writes a lookup parameter's subclass marker as
AcDbBlockLookUpParameter; the DWG bridge reads AcDbBlockLookupParameter and
matches it exactly, so the parameter's name (303) and lookup action (94)
were lost in DWG files and AutoCAD's lookups stopped working (a visibility
change no longer resized the block). The bridge DXF now uses its spelling.

Found by driving AutoCAD on CADCraft's output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic blocks: carried parameter points are in a stretch frame where the block has them

AutoCAD evaluates actions from the dynamic block itself, so a parameter point
another action has moved out of a stretch frame still follows it. Testing the
current position instead changed a stretched label's width when its
visibility changed (Distance2 183.75 became 184.45; AutoCAD keeps 183.75).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic block grips: show and drag a dynamic reference's grips as AutoCAD does

A selected dynamic block reference shows its grips: an arrow at each end of a
distance, a square at a position, a down-pointing triangle for a visibility
or lookup list, only those its visibility state lists. Dragging an arrow
changes the distance along the parameter (snapped to its values; a typed
number sets it), a square moves the position, a list grip offers its
choices; actions and lookups follow, with a live preview.

doc: dynblock::grips, drag_grip; grip objects by graph id.
engine: blocks.reference.grips, blocks.reference.grip, Session::start_dyn_grip.
ui: canvas dynamic grips (GRIPDYNCOLOR-like token), list popup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Tests: read the shared DOOR fixture with LF line ends whatever the checkout gives

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic blocks: carried parameter points are in a stretch frame where the block has them

AutoCAD evaluates actions from the dynamic block itself, so a parameter point
another action has moved out of a stretch frame still follows it. Testing the
current position instead changed a stretched label's width when its
visibility changed (Distance2 183.75 became 184.45; AutoCAD keeps 183.75).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic grips: Ukrainian labels for the new commands; copy the hot grip instead of cloning

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Cody Vogt <18035288+codyvogt@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-13 05:47:27 -04:00
0d138c2954 Dynamic block references: distances, positions, stretch and move actions, lookups both ways (stacked on #860) (#878)
* Dynamic blocks: read parameters and actions from AutoCAD files

A dynamic block's evaluation graph (kept as foreign data since #528) is read
into a typed model, `cadcraft_doc::dynblock`, without changing the kept
data: parameters (linear with value sets, point, visibility states,
lookup, base point; polar, XY, rotation, alignment and flip by geometry)
and actions (stretch with its frame and moved vertices, lookup tables;
move, scale, rotate, flip, array, polar stretch by kind), each with its
graph id and the parameters it follows.

- `blocks.dynamic {name}` returns the model as JSON (handles as hex);
  `blocks.list` marks dynamic blocks.
- Counts and values come from the file: capped by the groups present,
  non-finite numbers and missing members skipped.
- Tests: a synthetic DOOR block (visibility, linear list, stretch, lookup),
  its survival through a save, damaged data, and the engine commands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic block references: their values and custom properties

A dynamic block reference's extension dictionary says which dynamic block it
shows (AcDbBlockRepresentation ▸ AcDbRepData) and the values it was given
(AppDataCache ▸ ACAD_ENHANCEDBLOCKDATA, one XRECORD per parameter graph id).
`dynblock::reference` reads them; a reference to the dynamic block itself
has the block's values.

- `dynblock::custom_properties`: the Properties palette's Custom section, in
  parameter order, only parameters shown in Properties: visibility state,
  lookup value worked out from the lookup tables (their "no match" name, e.g.
  Custom, when the inputs match no row), distances and point positions in
  drawing units (block units × the reference's scale), with the choices of
  each (states, lookup values, a distance's list).
- Properties: a dynamic block reference shows its dynamic block's name
  instead of its anonymous block's, and a read-only Custom section.
- `blocks.reference {handle}` returns the definition, values and properties.
- Tests: synthetic references (own values, an anonymous block scaled 2, a
  width no lookup row has), survival through a save, the engine command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic block references: change the visibility state

Choosing a visibility state (or a lookup value whose tables set only
visibility states) in Properties ▸ Custom, or `blocks.reference.set
{handle, name, value}`, changes a dynamic block reference as AutoCAD does:

- The reference gets a new anonymous block: its current one with the
  state's objects shown and the parameter's other objects hidden (matched
  to the dynamic block's objects by their AcDbBlockRepETag element tags).
  The old anonymous block goes when nothing else uses it.
- AutoCAD's link data is written: the new block's record carries
  AcDbBlockRepBTag (the dynamic block's record), copied objects keep their
  element tags, and the reference's AcDbBlockRepresentation data records the
  value (an existing value record is updated; a new one copies another
  reference's record for the same parameter when there is one).
- An attribute whose definition the state hides is written hidden (60).
- Changes CADCraft can't make yet (distances, positions, lookups that set
  them) are refused with a message and change nothing; Properties shows
  only what can change as a dropdown (`CustomProperty::editable`).
- Tests: the synthetic DOOR references (own values and an anonymous block),
  survival through a save, refusals, and the engine command with undo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic block references: distances, positions, stretch and move actions, lookup chaining

Linear distances (snapped to their value sets) and point positions can be
changed; the stretch and move actions that follow them run (listed vertices
or whole objects, multiplier and angle offset), parameters in an action's
selection are carried along, associative hatches refill from their
stretched outlines and the reference's attributes move with their
definitions. Lookup tables run both ways (a changed input gives its table's
lookup value, which sets the other tables' inputs). Connections are read in
either group order. Checked against AutoCAD's own references (*U10, *U12).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic block references: record changes in the history as AutoCAD does; full value data for new references

A changed reference's ACAD_ENHANCEDBLOCKHISTORY says what was done to it: a
visibility state or lookup value by property name, a distance or position as
the drag of its grips (GRIPLOC, how far each grip is from where the dynamic
block has it). A reference that had no data gets a record for everything
other references of the same dynamic block have, with its own values.
Templates come only from references of the same dynamic block; anonymous
copies have no units; boundary reactors follow the copies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic block history: record only the grips a change moves

AutoCAD's history holds the user's own drags; a grip that only moved with
another parameter (a stretch carrying it) gets no entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic block history: a distance by name, as typed in Properties

AutoCAD records a distance typed in Properties as the parameter's name and
value in block units (1071 id, 300 Distance2, 40 40.0), replacing drags of
its grips; positions stay grip drags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* DWG: dynamic block lookup parameters keep their name and lookup action

AutoCAD writes a lookup parameter's subclass marker as
AcDbBlockLookUpParameter; the DWG bridge reads AcDbBlockLookupParameter and
matches it exactly, so the parameter's name (303) and lookup action (94)
were lost in DWG files and AutoCAD's lookups stopped working (a visibility
change no longer resized the block). The bridge DXF now uses its spelling.

Found by driving AutoCAD on CADCraft's output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic blocks: carried parameter points are in a stretch frame where the block has them

AutoCAD evaluates actions from the dynamic block itself, so a parameter point
another action has moved out of a stretch frame still follows it. Testing the
current position instead changed a stretched label's width when its
visibility changed (Distance2 183.75 became 184.45; AutoCAD keeps 183.75).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Cody Vogt <18035288+codyvogt@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-13 05:45:56 -04:00
f8521ab299 Dynamic block references: change the visibility state (stacked on #853) (#860)
* Dynamic blocks: read parameters and actions from AutoCAD files

A dynamic block's evaluation graph (kept as foreign data since #528) is read
into a typed model, `cadcraft_doc::dynblock`, without changing the kept
data: parameters (linear with value sets, point, visibility states,
lookup, base point; polar, XY, rotation, alignment and flip by geometry)
and actions (stretch with its frame and moved vertices, lookup tables;
move, scale, rotate, flip, array, polar stretch by kind), each with its
graph id and the parameters it follows.

- `blocks.dynamic {name}` returns the model as JSON (handles as hex);
  `blocks.list` marks dynamic blocks.
- Counts and values come from the file: capped by the groups present,
  non-finite numbers and missing members skipped.
- Tests: a synthetic DOOR block (visibility, linear list, stretch, lookup),
  its survival through a save, damaged data, and the engine commands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic block references: their values and custom properties

A dynamic block reference's extension dictionary says which dynamic block it
shows (AcDbBlockRepresentation ▸ AcDbRepData) and the values it was given
(AppDataCache ▸ ACAD_ENHANCEDBLOCKDATA, one XRECORD per parameter graph id).
`dynblock::reference` reads them; a reference to the dynamic block itself
has the block's values.

- `dynblock::custom_properties`: the Properties palette's Custom section, in
  parameter order, only parameters shown in Properties: visibility state,
  lookup value worked out from the lookup tables (their "no match" name, e.g.
  Custom, when the inputs match no row), distances and point positions in
  drawing units (block units × the reference's scale), with the choices of
  each (states, lookup values, a distance's list).
- Properties: a dynamic block reference shows its dynamic block's name
  instead of its anonymous block's, and a read-only Custom section.
- `blocks.reference {handle}` returns the definition, values and properties.
- Tests: synthetic references (own values, an anonymous block scaled 2, a
  width no lookup row has), survival through a save, the engine command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic block references: change the visibility state

Choosing a visibility state (or a lookup value whose tables set only
visibility states) in Properties ▸ Custom, or `blocks.reference.set
{handle, name, value}`, changes a dynamic block reference as AutoCAD does:

- The reference gets a new anonymous block: its current one with the
  state's objects shown and the parameter's other objects hidden (matched
  to the dynamic block's objects by their AcDbBlockRepETag element tags).
  The old anonymous block goes when nothing else uses it.
- AutoCAD's link data is written: the new block's record carries
  AcDbBlockRepBTag (the dynamic block's record), copied objects keep their
  element tags, and the reference's AcDbBlockRepresentation data records the
  value (an existing value record is updated; a new one copies another
  reference's record for the same parameter when there is one).
- An attribute whose definition the state hides is written hidden (60).
- Changes CADCraft can't make yet (distances, positions, lookups that set
  them) are refused with a message and change nothing; Properties shows
  only what can change as a dropdown (`CustomProperty::editable`).
- Tests: the synthetic DOOR references (own values and an anonymous block),
  survival through a save, refusals, and the engine command with undo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* DWG: dynamic block lookup parameters keep their name and lookup action

AutoCAD writes a lookup parameter's subclass marker as
AcDbBlockLookUpParameter; the DWG bridge reads AcDbBlockLookupParameter and
matches it exactly, so the parameter's name (303) and lookup action (94)
were lost in DWG files and AutoCAD's lookups stopped working (a visibility
change no longer resized the block). The bridge DXF now uses its spelling.

Found by driving AutoCAD on CADCraft's output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Cody Vogt <18035288+codyvogt@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-13 05:44:18 -04:00
73b8edac61 Dynamic block references: custom properties in Properties (stacked on #838) (#853)
* Dynamic blocks: read parameters and actions from AutoCAD files

A dynamic block's evaluation graph (kept as foreign data since #528) is read
into a typed model, `cadcraft_doc::dynblock`, without changing the kept
data: parameters (linear with value sets, point, visibility states,
lookup, base point; polar, XY, rotation, alignment and flip by geometry)
and actions (stretch with its frame and moved vertices, lookup tables;
move, scale, rotate, flip, array, polar stretch by kind), each with its
graph id and the parameters it follows.

- `blocks.dynamic {name}` returns the model as JSON (handles as hex);
  `blocks.list` marks dynamic blocks.
- Counts and values come from the file: capped by the groups present,
  non-finite numbers and missing members skipped.
- Tests: a synthetic DOOR block (visibility, linear list, stretch, lookup),
  its survival through a save, damaged data, and the engine commands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic block references: their values and custom properties

A dynamic block reference's extension dictionary says which dynamic block it
shows (AcDbBlockRepresentation ▸ AcDbRepData) and the values it was given
(AppDataCache ▸ ACAD_ENHANCEDBLOCKDATA, one XRECORD per parameter graph id).
`dynblock::reference` reads them; a reference to the dynamic block itself
has the block's values.

- `dynblock::custom_properties`: the Properties palette's Custom section, in
  parameter order, only parameters shown in Properties: visibility state,
  lookup value worked out from the lookup tables (their "no match" name, e.g.
  Custom, when the inputs match no row), distances and point positions in
  drawing units (block units × the reference's scale), with the choices of
  each (states, lookup values, a distance's list).
- Properties: a dynamic block reference shows its dynamic block's name
  instead of its anonymous block's, and a read-only Custom section.
- `blocks.reference {handle}` returns the definition, values and properties.
- Tests: synthetic references (own values, an anonymous block scaled 2, a
  width no lookup row has), survival through a save, the engine command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* DWG: dynamic block lookup parameters keep their name and lookup action

AutoCAD writes a lookup parameter's subclass marker as
AcDbBlockLookUpParameter; the DWG bridge reads AcDbBlockLookupParameter and
matches it exactly, so the parameter's name (303) and lookup action (94)
were lost in DWG files and AutoCAD's lookups stopped working (a visibility
change no longer resized the block). The bridge DXF now uses its spelling.

Found by driving AutoCAD on CADCraft's output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Cody Vogt <18035288+codyvogt@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-13 05:42:37 -04:00
fbc7037a10 Dynamic blocks: read parameters and actions from AutoCAD files (#838)
* Dynamic blocks: read parameters and actions from AutoCAD files

A dynamic block's evaluation graph (kept as foreign data since #528) is read
into a typed model, `cadcraft_doc::dynblock`, without changing the kept
data: parameters (linear with value sets, point, visibility states,
lookup, base point; polar, XY, rotation, alignment and flip by geometry)
and actions (stretch with its frame and moved vertices, lookup tables;
move, scale, rotate, flip, array, polar stretch by kind), each with its
graph id and the parameters it follows.

- `blocks.dynamic {name}` returns the model as JSON (handles as hex);
  `blocks.list` marks dynamic blocks.
- Counts and values come from the file: capped by the groups present,
  non-finite numbers and missing members skipped.
- Tests: a synthetic DOOR block (visibility, linear list, stretch, lookup),
  its survival through a save, damaged data, and the engine commands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* DWG: dynamic block lookup parameters keep their name and lookup action

AutoCAD writes a lookup parameter's subclass marker as
AcDbBlockLookUpParameter; the DWG bridge reads AcDbBlockLookupParameter and
matches it exactly, so the parameter's name (303) and lookup action (94)
were lost in DWG files and AutoCAD's lookups stopped working (a visibility
change no longer resized the block). The bridge DXF now uses its spelling.

Found by driving AutoCAD on CADCraft's output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dynamic blocks: a work budget on the record cursor, so counts promising missing groups can't make nested loops rescan a hostile record (with regression test)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Cody Vogt <18035288+codyvogt@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-13 05:40:12 -04:00
dc92f38772 DXF: count the records the reader can't place; info reports them, convert warns (part of #865) (#872)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 05:31:58 -04:00
1c4d0a543f Open damaged DWGs partially and say what was left out (#800) (#859)
Bump acadrust to 0.6.4 and read DWG in its failsafe mode: an object
record the reader can't decode is skipped instead of failing the whole
file. The drawing's new read_notes (never saved) say how many records
were left out and of which types; OPEN echoes them, returns them as
`warnings`, and the app shows the first in the status bar. A file whose
objects stream can't be read at all is still an error.

acadrust 0.6.4 writes a merged table cell's anchor with 173=0 and the
span, so the DXF reader now takes a merge from the span alone. Unknown
records the DWG writer can't write back are dropped before writing.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-13 05:30:18 -04:00
2f5bbbd68d doc: Space::tab_name / layout / is_paper replace repeated hand-written matches (#888)
* doc: Space::is_paper/layout/tab_name helpers replace hand-written matches

Twenty-seven call sites in 15 files across engine, io and ui-egui matched Space by hand to get
"is this a layout", "which layout" or "Model or the layout's name". Route them
through three small helpers on Space instead. No behaviour change.

This also makes adding a space kind a few-file change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* doc: keep Space::Model comparisons that no helper shortens; test the helpers

Only the sites that repeated the same match (tab name, layout name,
paper lineweights) go through the helpers; plain Model comparisons and
plot_window's match on (space, plotArea) stay as they were.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-13 05:21:19 -04:00
966356545d ACAD_TABLE from other writers: keep style text height, read cell text height, lay out cell text as MTEXT (#802) (#806)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-13 05:18:23 -04:00
63b448bee9 Extents: count the visible attributes of a reference to a missing block (fixes #707) (#746)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 05:12:00 -04:00
79efd97515 MTEXT: annotative scaling and SCALE on multileader text scale the text width and columns too (fixes #708, fixes #709) (#743)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 05:10:24 -04:00
724c18c6af Constraint point names: s2 names segment 2, as documented (fixes #710) (#734)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 05:04:26 -04:00
mattlafyandClaude Opus 5.5 d134079f11 Xdata travels with its object: COPY, MIRROR, ARRAY and paste keep it (#890)
Other applications' xdata on an entity was kept beside the drawing,
keyed by handle, so a copy (new handle) lost it: a copied hyperlink
(PE_URL) had no link, third-party tags stayed on the original only.
In AutoCAD xdata is part of the object.

Move entity xdata onto the entity as Common::xdata (the same raw
groups); every copy path already clones Common. The DXF reader puts it
there (handle references still noted for remapping), the writer takes
it from the entity, PDF hyperlinks come from the entities. EXPLODE's
pieces of an object don't inherit its xdata. Table record and block
xdata stay in Foreign.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 04:38:34 -04:00
Valentin KleinandClaude Sonnet 5.5 9464945f82 REFEDIT, REFSET and REFCLOSE: edit block references in place (#818)
* REFEDIT, REFSET and REFCLOSE: edit block references in place (#813)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Move REFEDIT translation lines into the middle of the catalogs (avoids PR merge conflicts)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 04:37:31 -04:00
aldozarandClaude Opus 5.5 e9d8462828 Keep the ACIS geometry of 3D solids, regions and bodies on save (ACDSDATA) (#781)
From AutoCAD 2013 on, a 3DSOLID, REGION or BODY doesn't carry its ACIS
geometry: the binary SAB lives in the file's data store section (ACDSDATA),
one ACDSRECORD per entity bound by a 320 handle. CADCraft kept those
entities (as unknown entities, with their handles) but dropped the section,
so a drawing saved as DWG or DXF had empty solids, and saving reported them
as not saved.

- doc: Foreign::data_store keeps the section's groups as read;
  data_store_entities() lists the entities it has records for.
- io: the reader keeps the section; the writer puts it back for files of
  2013 and later (and in the DXF the DWG bridge converts, which acadrust
  reads into the DWG), without the records of entities no longer written.
  Nothing is written for older files or when no record's entity remains.
- engine: not_saved_as(d, version): from 2013 a solid, region or body with a
  data store record isn't reported; saves and document.bytes pass the version
  being written.

On a 39,600-object permit set with 625 3D solids and 2 regions, DWG ->
CADCraft -> DWG now keeps all 627 bodies with byte-identical SAB (before:
none), and the save no longer reports them.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 04:35:31 -04:00
Marco Arnulfo 565cadaa51 Extents: cache block bounds per depth so a deep visit can't hide a shallow reference (fixes #706) (#778) 2026-10-13 04:35:20 -04:00
aldozarandClaude Opus 5.5 6ca8cec97d BRICK: draw each vertical joint once (#664)
Squash of PR #664 by @aldozar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:11:25 -04:00
aldozarandClaude Opus 5.5 135c928fea Hatches: draw the pattern definition stored in the file; scale library patterns in metric drawings (#643)
Squash of PR #643 by @aldozar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:54:18 -04:00
PedroGuilleandClaude Opus 5.5 f967dc7aca Persist SNAPUNIT and GRIDUNIT in DXF (fix #607) (#614)
Squash of PR #614 by @PedroGuille.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:28:56 -04:00
MarekSpodBiedryandClaude Opus 5.5 5cb54c3969 Include multileader text in its bounds so zoom, window selection and viewports keep the whole text (#488) (#600)
Squash of PR #600 by @MarekSpodBiedry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:04:24 -04:00
Valentin KleinandClaude Opus 5.5 74e72c93f8 Plotters: device configurations with paper sizes and printable areas (fixes #564) (#570)
Squash of PR #570 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:25:00 -04:00
Valentin KleinandClaude Opus 5.5 9fd1b8988d Support files: user .lin linetypes and .pat hatch patterns (part of #552) (#557)
Squash of PR #557 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:12:17 -04:00
Valentin KleinandClaude Opus 5.5 58eefa8432 Constraints: DOF report, G2 Smooth, ellipse/spline/block geometry (part of #546) (#550)
Squash of PR #550 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:47:53 -04:00
Valentin KleinandClaude Opus 5.5 9ca0dcf7d4 Tables: table breaking and CSV data links (fixes #534) (#553)
Squash of PR #553 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:47:39 -04:00
Valentin KleinandClaude Opus 5.5 784a7937ef Tables: cell styles, formulas, TABLEDIT and TABLEEXPORT (part of #534) (#548)
Squash of PR #548 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:47:25 -04:00
Valentin KleinandClaude Opus 5.5 8005201db9 feat(text): MTEXT paragraph formatting (indents, tabs, lists) and columns (#547)
Squash of PR #547 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:47:12 -04:00
Valentin KleinandClaude Opus 5.5 a4504cc098 DXF: keep what we don't model on save — unknown entities and objects, foreign xdata, extension dictionaries, reactors, colour books (fixes #528) (#545)
Squash of PR #545 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:46:58 -04:00
Valentin KleinandClaude Opus 5.5 afae36cb60 REGION: region entity, UNION/SUBTRACT/INTERSECT, MASSPROP (fixes #510) (#526)
Squash of PR #526 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:12:09 -04:00
Valentin KleinandClaude Opus 5.5 0230250bf5 Xrefs: XATTACH, -XREF, XBIND, XOPEN; load at open, save only the reference (part of #525) (#530)
Squash of PR #530 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:11:37 -04:00
Valentin KleinandClaude Opus 5.5 c334fedf31 Dimension edits: DIMEDIT Oblique/New/Rotate/Home, DIMJOGGED, DIMJOGLINE, DIMBREAK, DIMINSPECT (part of #507) (#522)
Squash of PR #522 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:10:38 -04:00
Valentin KleinandClaude Opus 5.5 b7b37e29cd HELIX: helix entity drawn as a spline (part of #510) (#521)
Squash of PR #521 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:10:24 -04:00
Valentin KleinandClaude Opus 5.5 289855aa67 MLINE: multiline entity, MLSTYLE and MLEDIT (part of #510) (#517)
Squash of PR #517 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:48:27 -04:00
Valentin KleinandClaude Opus 5.5 836badce4c Dimension styles: fit, text movement, suppressed halves, fixed extension lines, linetypes and lineweights and more DIM variables (part of #507) (#514)
Squash of PR #514 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:47:57 -04:00
Valentin KleinandClaude Opus 5.5 7ecac5fb66 Tiled model viewports: VPORTS, saved viewport configurations, DXF VPORT table (part of #463) (#504)
Squash of PR #504 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:43:11 -04:00
Valentin KleinandClaude Opus 5.5 c9c3031de9 Named views (VIEW), Zoom Realtime and Dynamic, ZOOMFACTOR (part of #463) (#503)
Squash of PR #503 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:42:56 -04:00
Valentin KleinandClaude Opus 5.5 e7bb447d58 Annotative scaling: scale list, CANNOSCALE, OBJECTSCALE, ANNOALLVISIBLE (part of #468) (#486)
Squash of PR #486 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:42:13 -04:00
Valentin KleinandClaude Opus 5.5 d42313cde2 ARRAYEDIT and ARRAYCLOSE for associative arrays (fixes #448) (#460)
Squash of PR #460 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:36:02 -04:00
Valentin KleinandClaude Opus 5.5 61a8a5f984 Viewports: polygonal, object and clipped viewports, VPCLIP, MVIEW ON/OFF/Lock/Restore (part of #453) (#458)
Squash of PR #458 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:35:46 -04:00
Valentin KleinandClaude Opus 5.5 bd2a7597c5 Associative arrays: ASsociative, Levels and polar ROWs (part of #448) (#455)
Squash of PR #455 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:28:48 -04:00
Valentin KleinandClaude Opus 5.5 e02d1ebd08 Hatch: associative hatches follow their boundary objects; DXF 97/330 source objects (part of #451) (#454)
Squash of PR #454 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:28:33 -04:00
Valentin KleinandClaude Opus 5.5 9b136d6c19 Draw order: DRAWORDER Above/Under objects, TEXTTOFRONT, HATCHTOBACK, SORTENTSTABLE read (part of #439) (#446)
Squash of PR #446 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:23:59 -04:00
Valentin KleinandClaude Opus 5.5 65d5ee48d3 SELECTSIMILAR and object isolation: ISOLATEOBJECTS, HIDEOBJECTS, UNISOLATEOBJECTS (part of #428) (#434)
Squash of PR #434 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:20:02 -04:00
Valentin KleinandClaude Opus 5.5 9e3379882f TOLERANCE: GD&T feature control frames (fixes #420) (#427)
Squash of PR #427 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:19:32 -04:00
Valentin KleinandClaude Opus 5.5 fc4220e9b7 Plot styles: named styles (STB), PLOTSTYLE, STYLESMANAGER and table files (part of #410) (#418)
Layers and objects get a PlotStyle property (ByLayer/ByBlock/name) applied
through named tables (built-in default.stb and monochrome.stb, our own
definitions). DXF keeps the names in the ACAD_PLOTSTYLENAME dictionary of
ACDBPLACEHOLDER objects with group 390 on layers and objects; tables kept in
the drawing travel in a CADCRAFT_PLOTSTYLES XRECORD. PLOTSTYLE sets an object's
or the current (CPLOTSTYLE) style; STYLESMANAGER lists, creates, edits, deletes,
loads and saves tables in our own JSON format (docs/plot-styles.md). A Plot
Style Manager dialog edits a table's styles and the layout's table; the
Properties palette shows the current plot style and table.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:21:24 -04:00