A plot style alone drew black lines on the dark canvas: the tables that
change colours print colour 7 (and, in monochrome.ctb, every colour)
black. With `plot_style` and no `background`, the render now draws on
white, as a plot prints on paper; a given background still wins.
`plot_style: "none"` (or "") draws every object with its own
properties, also in a layout that shows its own plot styles. An unknown
table's error lists the built-in tables and at most ten of the
drawing's own. The app's ui.render test now draws a red line, so it
fails if the plot style isn't passed on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The MCP render tool and ui.render, in the app and headless, always drew
on the dark canvas with no plot style, so a PNG placed on a page needed
the SVG export instead.
They now take `background` ("dark", the default; "white", "paper" or
"#rrggbb") and `plot_style` (a built-in plot style table such as
monochrome.ctb or grayscale.ctb, or one the drawing holds). Colour 7 is
drawn black on a light background and white on a dark one, as on a plot.
An unknown value is refused with what is accepted. Both copies of
ui.render read the options through one function in the engine
(render_look). The render tool's description also says it returns an
image block, not text.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Choosing ka, its English fallback and the picker name come with the
language PR (#2016), which registers ka; this PR alone doesn't.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* DWG: a table cell's text height is an override only when the file flags it (#2501)
acadrust's DXF writer writes group 140 for any cell with a style record, even a
default 0.18 with no override flag, and CADCraft read it as a per-cell height,
so cells ignored the table style's height. The bridge now clears the height of a
cell style that has neither the TEXT_HEIGHT property flag nor the content's
height override bit (0 reads as no override).
* Parity checklist: regenerated after merging main
* Tests: inherited table cell heights must stay unset (review on #2588)
A cell that inherits its height must read back as None, not an explicit 0.0625 override.
* Parity checklist: regenerated after merging main
* Test: a cell style with the TEXT_HEIGHT flag, content override bit 128 and a cell with no style record keep the right height (review on #2588)
* DWG: a table cell's content height override (group 144) is kept (review on #2588)
* Parity checklist: regenerated after merging main
* DWG: table cell height takes the first content's override and the style's override flags (review on #2588)
Only the first content's bit-128 height stands for the cell (one height for its text); an
invalid content height no longer keeps the writer's default 0.18; a height marked only in
the style's override flags (newer files) is kept.
A damaged DWG opens partially since #859 and the drawing's read notes
say how many object records were left out. OPEN echoes them and MCP
`open` returns them as `warnings`, but `cadcraft-cli info` and
`convert` stayed silent: a corpus round trip wrote thousands of skipped
records away without a word.
- convert: each read note goes to stderr as `IN: <note>`, next to the
skipped-records warning (#872). The exit code stays 0.
- drawing.inspect (and so info, MCP inspect_drawing and the control
channel): new field `readNotes`, next to `skipped`. Existing fields
are unchanged.
- run already prints OPEN's notes with the session log.
- README and docs/control-protocol.md say where the notes appear.
Part of #1039.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* i18n(pt-BR): translate the rows the sibling catalogs cover
The Brazilian Portuguese catalog covered the reference catalog and every marked UI literal, but 191
strings that the German, French, Swedish and Ukrainian catalogs already translate still fell back to
English: the Hatch and Gradient dialog, the Block Editor and dynamic-block grips, the plot and drawing
units dialogs, multileader editing, selection preview settings and the unit names.
Rows follow the catalog's vocabulary (dimension = cota, hatch = hachura, grip = pinça, layout =
apresentação, multileader = multilinha, xref = referência externa), keep the prompt keywords, SPDX
tokens and technology names in English, and are appended after the existing entries.
* docs: leave localization parity updates to maintainers
Without a native picker the Import… message told users to give ALIASEDIT a
path, but the web has no file system and rejects paths. Name the supported
route instead: the file's contents in ALIASEDIT's text parameter. The
Ukrainian reference translation and the customization docs follow the new
wording; the desktop picker path is unchanged.
ALIASEDIT kept its aliases in a process-wide store and nothing saved or
restored them, so they were gone after a restart. The engine now gives
the set and the alias file REINIT reads to the host profile
(alias_profile) and restores them (restore_aliases) in CadApp's
profile_json / load_profile, bounded and safe on a malformed saved set;
command names still win. The Command Aliases dialog says where the
aliases are kept.
* DXF: no CLASS instance counts in R2000 files (AutoCAD LT 2026 hung on them)
Since #635 every CLASS record carries group 91, the instance count, at every
version. The count came with the 2004 format: R2000 CLASS records are 1, 2, 3,
90, 280, 281. AutoCAD LT 2026 stops responding when it opens an R2000 DXF
whose CLASS records have a 91, so every R2000 file CADCraft saved locked it up
(a drawing opened from an R2000 file is saved as R2000 again).
Isolated black-box in AutoCAD LT 2026 with synthetic files: the same R2000
file without the 91 groups opens, as does the same content declared AC1032.
The counts are now written only when the file (or the DWG the bridge writes)
is 2004 or later; R2000 output drops the group from every CLASS record,
classes kept from a newer file included.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Test: binary R2000 drops group 91 from a kept foreign CLASS too
Review follow-up: the kept-class check covered R2000 only through ASCII
saves; it now also saves the fixture as binary R2000 and checks that the
ACME_OBJECT CLASS record is 1, 2, 3, 90, 280, 281.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Test: binary 2018 keeps a kept foreign CLASS's instance count
Review follow-up: the kept-class check now saves the fixture as binary at
both R2000 (no group 91) and 2018 (group 91 after the proxy flags, with the
class's count), through one helper.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Slopapalooza <307952167+Slopapalooza@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Add Bosnian (bs) to the interface languages
bs.tsv: Bosnian (Latin script, Ijekavian) catalog covering every key of
CADCraft's other catalogs, its wording shared with storytold/craft-i18n
locales/bs/ and the strings craft-i18n lacks translated new. Every bs-*
locale selects it; counts use one/few/other. Locale and plural tests,
localization docs and an attribution entry (AI-assisted, not yet
reviewed by a native speaker).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013Tayw8nmxoLLmKv13jK93z
* docs(localization-parity): Bosnian in the Languages table (CodeRabbit)
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Extents: an MTEXT's wrap width only narrows its box (#2465)
A garbage group 41 width (3e14) became the box width, so the drawing extents were 3e14
wide. The width is now capped at the longest line's estimate. The width 0 branch is
unchanged. Tests: a_huge_mtext_wrap_width_does_not_inflate_the_extents and
a_narrow_mtext_wrap_width_still_sets_the_box_width.
* Parity checklist: regenerated after merging main
* Parity checklist: regenerated after merging main
* LISP: getvar and setvar take angle variables in radians
CADCraft keeps ANGBASE, SNAPANG, POLARANG, HPANG, CHAMFERD and
DIMJOGANG in degrees as far as sysvars::get/set go, which is right for
the SETVAR command, but AutoLISP's getvar returned those degrees and
setvar took them: (getvar "DIMJOGANG") gave 45.0, and
(setvar "ANGBASE" (/ pi 2)) set 1.57 degrees.
AutoCAD 2024 gives and takes them in radians from AutoLISP: each set to
30 by SETVAR, or to (/ pi 6) by setvar, reads 0.5235987755982987. The
LISP bridge now converts these six; the SETVAR command is unchanged.
getangle_is_relative_to_angbase sets ANGBASE in radians accordingly.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* SETVAR: keep real dimension variables real
A dimension variable whose style field is a real (DIMJOGANG, DIMSCALE
and the other real DIM* fields) is now stored as a real header value,
even when the first value set is a whole number. SETVAR DIMJOGANG 45
followed by (setvar "DIMJOGANG" 0.5) no longer rejects the fractional
degrees the radian value gives.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* SETVAR: store the value the dimension style took
A real dimension variable now stores the value its style field took after validation, so any input the style accepts (true for DIMSCALE gives 1) is stored as it was before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* LISP: entity names answer prompts that pick one object
`command` fed an entity name, alone or as `entsel` returns it (name and
point), to the running command as a pick. Prompts that pick a single
object with a point (MEASURE, DIVIDE, LENGTHEN, PEDIT, BREAK, TRIM and
EXTEND in Standard mode, FILLET, OFFSET, REVCLOUD Object, dimensions…)
only take points, so routines got "Invalid input" or nothing at all.
At such a prompt the name is now entered as its point, and a pick at
exactly that point finds the named object (Session::pick_object), so
the point says where on it, as in AutoCAD. A bare name stands at the
object's DXF group 10 point, the point AutoCAD picks it at: a line's
start, a circle's or an arc's centre, a polyline's first vertex. At an
arc's centre MEASURE runs from the arc's end, as AutoCAD does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Keep a named object for its own input and its own space
A name given at a prompt picking one object now holds only while that
input is taken: a later pick at the same point finds what lies there.
A name for an object in another space picks nothing, instead of the
object under its point in the current space.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
An IMAGE whose file exists was drawn as a frame with two diagonals. Now
its pixels are loaded when a drawing opens and drawn on screen and in PNG
output, with rotation, clip boundary, fade and object transparency. A file
that can't be read keeps the crossed-out frame and reports a message.
Ported from the raster commit of #1029 onto the split render and canvas
modules. New here: large images are drawn from a pyramid of levels cut
into tiles uploaded as they come into view, instead of one texture with
pixels skipped, so a large scan stays sharp zoomed in and doesn't shimmer
zoomed out.
Limits are listed in docs/gaps.md (FF10): PDF and SVG output write only
the frame, and on screen images lie under all other objects.
Co-Authored-By: Chanthawat Kiriyadee <enwuft@icloud.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>