Commit Graph
462 Commits
Author SHA1 Message Date
8166e4a809 AutoLISP: load and run .lsp routines (fixes #758) (#855)
* AutoLISP: load and run .lsp routines (#758)

CADCraft runs AutoLISP routines. `.lsp` files load with APPLOAD, (load)
or by dropping them on the window, and at startup from the support folder
(acad.lsp once per session or per drawing with ACADLSPASDOC, acaddoc.lsp
per drawing, then S::STARTUP; never from a drawing's own folder).
(defun c:NAME …) defines commands, (autoload) defers loading to first
use, and (expression) and !variable work at the command line and at
prompts. docs/autolisp.md lists what is supported.

The interpreter (crates/engine/src/lisp) reads source with its own
stack and evaluates on an explicit-stack machine, so a routine can stop
for input (getpoint, pause in command) and carry on later on one thread,
deep recursion is an error rather than a crash, and long loops run a
slice per frame (Esc stops them). It follows AutoLISP: 32-bit wrapping
integers, dynamic scope, *error*, vl-catch-all-apply, AutoLISP's error
wording. About 200 built-ins cover the language, command (with pause and
commands left open), entity lists (entget/entmake/entmod/entdel/entlast/
entnext/handent, through the DXF reader and writer's groups, exposed by
cadcraft-io and handed to the engine through a hook), ssget with modes
and filters, tables, system variables, get… input with initget, and
units. A routine is one undo step; each drawing has its own symbols.

Also: keywords typed as _KEYWORD match at prompts; TEXT run by a
routine's command takes one line; DIMENSION records carry their
measurement (42); Prompt::raw shows a get… prompt as written; the
interface asks Session::prompting() (a command's or a routine's prompt)
where it asked whether a command runs, so clicks, right-click and Delete
work at a routine's prompts; getcorner and based get… prompts drag a
rubber band.

Tests: the language, errors, startup files, interactive input, hostile
input (lisp/tests.rs); the #648 corpus, 18/18, when CADCRAFT_LISP_CORPUS
points at it (tests/lisp_corpus.rs); drop, frames and canvas clicks in
the app (ui-egui/tests/lisp_files.rs).

* AutoLISP: bound memory, drop nested values iteratively, guard the per-frame tick

- Cons cells drop with a work list over both car and cdr (and function
  bodies), so a list nested a million deep in its car no longer overflows
  the stack when it goes away.
- Memory caps so a runaway routine fails with a LISP error instead of an
  uncatchable out-of-memory abort: at most 5,000,000 live cons cells
  (counted in Value::cons / Drop, checked every step; cells the drawing's
  variables already held at the run's start don't count against it), no
  string a built-in makes longer than 8 MiB (strcat checks before joining,
  printed text is cut), and a 2 GiB per-run budget for new strings,
  printed text and files read.
- Session::lisp_tick runs under catch_unwind, and so does every slice of
  the LISP machine: a panic ends the routine with "internal error", puts
  the drawing back and leaves the session usable.
- Regression tests for each (deep car nesting, nested functions, the cell
  cap, string length and budget, a panicking built-in in a blocking run
  and in a ticked one).

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:33:57 -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 <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
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 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
2026-10-13 05:30:18 -04:00
Brandon ThomasandClaude Opus 5.5 ef9898d57f zh: drop two duplicate rows left by merging #870 and #884
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 05:29:13 -04:00
33fe98a6dc Update Chinese translations in zh.tsv (#884)
* Add Chinese language support to preferences

* Add Chinese language support to preferences

* Chinese: register it as a reported language and draw it with an installed CJK font

The catalog didn't compile (Self::SimplifiedChinese) and egui's bundled
fonts have no Chinese glyphs, so the interface would have shown boxes.
Fonts are never bundled: the interface now looks for an installed CJK
font (PingFang, Microsoft YaHei, Noto Sans CJK, WenQuanYi...) and adds it
after the Latin fonts when Chinese is shown. Without one the interface
stays in English and says why. ATTRIBUTION row; language lists updated.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Update Chinese translations in zh.tsv

* zh: drop a stray 外形 from the array limit message

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:24:22 -04:00
5630529464 Properties palette: numeric fields take feet and inches, show lengths in the drawing's units, and report what they can't read (fixes #849) (#870)
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:23:59 -04:00
3b16f2d516 Engine: run the post-command passes from one place (#856)
`execute` and the interactive `finish` each called the group, constraint and
associativity passes in sequence, with slightly different arguments. They now
both call `Session::after_command(before, uid, ok)`, which lists the passes
once, so a pass cannot be added on one path and missed on the other. The
arguments each path passed are unchanged: `execute` passes the document uid and
`undoable && ok`; `finish` passes no uid and `true`.

tests/post_command_passes.rs pins that MOVE and ERASE, run through `execute`
and typed, prune groups, purge/re-solve constraints and update an associative
hatch identically, in one undo step that undo fully reverses.

Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
2026-10-13 05:23:39 -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 <[email protected]>

* 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 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
2026-10-13 05:21:19 -04:00
76b0ef8897 Select: pick a solid hatch inside its fill, islands left out, not its bounding rectangle (follow-up to #747) (#763)
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:20:39 -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 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
2026-10-13 05:18:23 -04:00
4257674dfa Fix polyline offset arc bulge after joining moved endpoints (#817) (#825)
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:17:25 -04:00
64b7825d08 Property-based and hostile-input tests for geometry numerics (gaps.md S6) (#733)
* Property-based and hostile-input tests for geometry numerics (gaps.md S6)

A deterministic xorshift64* generator (no new dependency) drives a few
thousand cases per property in crates/geom/src/property_tests.rs:

- line/line: hits lie on both lines, parameters reproduce the point,
  swapping the operands gives the same point, finite results agree with
  the infinite parameters
- line/circle and circle/circle: hits lie on both curves, results are
  symmetric, properly crossing circles match the closed form; hostile
  inputs (NaN, infinities, subnormals, raw bit patterns, 1e300) never
  panic and the guarded functions return only finite hits or none
- segments: extending only adds hits
- closest points: fixed point of closest, perpendicular inside the
  segment, endpoints outside
- arcs: at(0)/at(1) are the endpoints at radii from 1e-6 to 1e6; the
  three-point arc keeps {start, end} = {p1, p3} and contains p2 (the
  CCW-only storage swaps the pair when p2 is on the clockwise side, as
  DXF stores arcs) and matches the circumradius closed form; collinear
  inputs are rejected
- bounds and vector identities
- known answers at 1e6-1e7 coordinates hold to 1e-9 relative

gaps.md S6 removed and geometry-parity.md's Tests section updated in
the same change.

* docs: drop the sentence the new numerics tests make stale

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:16:44 -04:00
d2a9159e51 PDFBOOK: plot sheet frames in model space into one PDF per row of frames (#896)
* PDFBOOK: plot sheet frames in model space into one PDF per row of frames

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>

* PDFBOOK: no Cmd+Shift+P shortcut (AutoCAD's Quick Properties toggle); simpler uk label

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: simanov <[email protected]>
Co-authored-by: Claude Sonnet 5.5 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
2026-10-13 05:15:56 -04:00
678ff555ae MTEXT: paragraph indents and tab stops are in drawing units (#895)
* MTEXT: paragraph indents and tab stops are in drawing units

AutoCAD writes \pi, \pl, \pr and tab stops in drawing units, not multiples of the text
height. A file with \pi27.485 on 6-high text in a 120-wide box laid out with a 165-unit first
line indent: the first line vanished and wrapped words landed elsewhere. The JSON mtext
parameters indent, firstIndent, rightIndent and tabs follow (a list's default indent is now
3 text heights, in drawing units).

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>

* MTEXT editor: list indent of three text heights in drawing units, matching the new \p units

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: simanov <[email protected]>
Co-authored-by: Claude Sonnet 5.5 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
2026-10-13 05:13:16 -04:00
d0438577ed Fonts: use the TrueType typeface from a style's xdata and find families by first word (#894)
AutoCAD stores a TrueType text style's family (e.g. "GOST type A") in the style's ACAD xdata
and leaves the font file name empty. Styles without a file now take that family.

Family-name lookups also look in files whose name starts with the family's first word, so
"GOST type A" finds GOST.TTF (the stem shares only 4 characters with the family name).

Co-authored-by: simanov <[email protected]>
Co-authored-by: Claude Sonnet 5.5 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
2026-10-13 05:12:33 -04:00
63b448bee9 Extents: count the visible attributes of a reference to a missing block (fixes #707) (#746)
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:12:00 -04:00
7b767ddab9 Plot: model-space PNG and SVG plots honour fit: false without a scale, at 1:1 like PDF (fixes #713) (#744)
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:10:52 -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 <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:10:24 -04:00
cddcbe7a2a Dimensions: a jogged radius with a NaN or infinite radius draws no lines instead of panicking (fixes #712) (#742)
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:09:44 -04:00
b209bb53e9 Geometry: param_at_length checks spline validity before clamping to the domain (fixes #704) (#741)
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:09:01 -04:00
5d39f8710c HATCHEDIT: choosing SOLID on a gradient hatch makes it a plain solid fill (fixes #721) (#740)
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:07:46 -04:00
6394c7c6f3 JOIN: an elliptical arc named twice is one object, so the joined result stays (fixes #725) (#739)
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:07:02 -04:00
2483993218 HATCH: a pattern name with no definition is refused instead of drawn as ANSI31 (fixes #722) (#736)
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:06:15 -04:00
cc57dff527 POLYGON: a typed radius of zero or less, or a radius point on the centre, is refused and asked again (fixes #720) (#735)
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:05:37 -04:00
724c18c6af Constraint point names: s2 names segment 2, as documented (fixes #710) (#734)
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:04:26 -04:00
8e0b867f6c BREAK, BREAKATPOINT and JOIN: leave objects on locked layers alone (fixes #727) (#730)
BREAK and BREAKATPOINT (break_entity) and line/arc/polyline JOIN
(modify::join) removed their source objects and added replacements
without checking the source layer's lock, so a locked line could be cut
or merged into a polyline. ERASE, MOVE, TRIM, FILLET, EXPLODE and the
ellipse/spline JOIN already guard against this.

Both now refuse with the same errors the sibling commands use:
"The object is on a locked layer." (BREAK, BREAKATPOINT, like FILLET)
and "An object is on a locked layer." (JOIN, like the ellipse/spline
join). JOIN refuses the whole request when any selected object is
locked, so a mixed-layer pair keeps its locked original in either
order. The guards sit in the shared functions, so JSON calls with
explicit handles or the selection, the interactive prompts and the
command line all reach them. The interactive commands report the
refusal on the command line.

Tests (crates/engine/tests/break_join_locked_layers.rs, red before the
fix): BREAK and BREAKATPOINT on a locked line by handle and by
selection; BREAK on a locked arc and circle; JOIN of locked lines and
of a locked/unlocked pair in both orders; interactive BREAK and JOIN.
Each checks the drawing is unchanged while locked, and that the same
edit works unlocked (BREAK also undoes and redoes).

Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:03:16 -04:00
36f938e90a Performance: restrict object-snap intersections to cursor aperture (#701)
* Snap: pin finite and apparent intersection behavior

* Snap: skip finite intersections outside the aperture

---------

Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:02:28 -04:00
Brandon ThomasandClaude Opus 5.5 636b041a4e DXF writer: resolve the #827/#871 merge (W keeps both the layer handles and the hatch reactors)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 04:51:37 -04:00
Brandon ThomasandClaude Opus 5.5 bb7e1046be docs: gaps F1/F2 rows after the STRETCH and REFEDIT merges (one row each)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 04:47:56 -04:00
f807e65e30 STRETCH: polygon and fence selection (#892)
At "Select objects", CP and WP take a polygon (Enter closes it) whose
inside marks the vertices that move, as a crossing window does; F takes a
fence, and what it crosses moves whole, like objects picked one at a
time. BOX works too, Undo takes back the last point, and the polygon or
fence is drawn while its points are placed.

The JSON form takes `polygon` or `fence` in place of `window`; both are
capped at the selection modes' point limit and refuse non-finite points.

Co-authored-by: Chanthawat Kiriyadee <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
2026-10-13 04:47:19 -04:00
69f2b9724a Save xref layer overrides with the host, in DXF and DWG (fixes #886) (#889)
A colour or freeze set in the host on an xref's layers (xref|layer) was lost on save:
the saved view dropped every xref-dependent symbol, layers included, and the DWG save goes
through the same DXF tags. The reader already keeps such layers when the xref loads.

The xref's layers are now written as xref-dependent LAYER records (DXF Reference, LAYER
group 70: 16 externally dependent, 32 resolved), as AutoCAD does with VISRETAIN = 1, with
the xref linetypes they use (same flags): without them a DWG falls back to Continuous.

Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 04:46:45 -04:00
28b8160407 DXF: associative hatches in blocks keep their boundary; boundaries carry the hatch reactor (#871)
A hatch inside a block was written with no source objects (the writer looked
for them in model and paper space only), and no boundary object carried the
hatch as a persistent reactor. AutoCAD keeps the two linked both ways; without
it a stretched dynamic block in AutoCAD moved the outline but not the fill.

Co-authored-by: Cody Vogt <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
2026-10-13 04:46:29 -04:00
5b037b8f92 DXF: write viewport frozen layers as group 341 layer handles too (#827)
A layout VIEWPORT's frozen layers were saved only as CADCraft's own
1001 CADCRAFT / 1000 VPFROZEN xdata. Other programs ignore that, so in
any third-party viewer every viewport showed every layer.

The writer now also emits the standard group 341: one soft pointer per
frozen layer to its LAYER table record handle, after 90/340 and before
the xdata. A frozen name with no LAYER record is skipped for 341 only
(the xdata still carries it). The reader keeps preferring the xdata; a
VIEWPORT without it (a file from another program) resolves its 341
handles through the LAYER records' group-5 handles, ignoring unknown
handles and keeping the 341 order.

Not covered: the DXF-to-DWG converter does not carry group 341 yet, so
a DWG keeps per-viewport freezing only through the CADCraft xdata.

Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
2026-10-13 04:46:15 -04:00
5fd23f75fc Command line: a bare system variable name runs SETVAR on it (part of U10) (#799)
* Command line: a bare system variable name runs SETVAR on it (part of U10)

Typing ORTHOMODE, PICKADD and the like at the command line returned
"unknown command". Session::start now falls back to SETVAR with the name
already entered when the text is not a command but is a known variable;
dash, dot and underscore prefixes never mean a variable, and real
commands still win. Read-only variables print their value, and the
transparent form ('OSMODE) resumes the interrupted command.

Checked: fmt, clippy, test, assets, layers and wasm pass; also driven
through the control channel in the running app.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>

* Tests: every variable name, command collisions and hostile input for bare SETVAR

Covers each variable SETVAR lists: a name that is not a command starts SETVAR
(or prints a read-only value), a name that is also a command keeps the command,
and odd input (lone apostrophes, NUL, wide characters, a 1 MiB name) never
panics and leaves the session usable. Disabling the fix makes all three new
and old tests fail.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 5.5 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
2026-10-13 04:46:00 -04:00
a6200fa34f i18n(pt-BR): complete the Brazilian Portuguese catalog (#791)
Add the 238 rows that still fell back to English, taking the catalog to
1,231 rows: it now covers the reference catalog and every marked UI
literal (commands, menus, tool groups and tooltips, object snaps,
drafting prompts, dialogs and Preferences), so the i18n tests report no
remaining gaps for pt-BR.

The translations follow the terminology already used in the catalog
(cota, hachura, camada, pinça, janela gráfica, referência a objetos) and
preserve placeholders ({n}, {name}) and trailing ellipses exactly.

Also add a bundled-font glyph test for the catalog's accented letters,
mirroring the German and Ukrainian ones, and record the completion in
docs/localization-parity.md (status line and revision history) and
docs/localization.md.

Written from CADCraft's English strings; no proprietary localization
resources were copied.

Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 04:45:43 -04:00
25e4900fcd Recent files: the Start page and File ▸ Open Recent list the drawings opened last (fixes #858) (#864)
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 04:44:44 -04:00
4efb01332e Canvas: every click places a point while drawing, however fast (fixes #815) (#835)
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 04:42:53 -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 <[email protected]>
2026-10-13 04:38:34 -04:00
ZaxaerithandZaxaerith 591692a264 docs: clarify engine commands in control protocol (#845) (#873)
Co-authored-by: Zaxaerith <[email protected]>
2026-10-13 04:38:29 -04:00
Marco Arnulfo 50246683c3 DXF: read every ENTITIES section, not only the last (fixes #865) (#869) 2026-10-13 04:38:24 -04:00
Marco Arnulfo 2effc8bf3e Double-click on text, mtext or an attribute definition starts TEXTEDIT on it (part of #842) (#868) 2026-10-13 04:38:18 -04:00
Marco Arnulfo 5b0238fc26 Dynamic Input and grip fields show distances in the drawing's UNITS (fixes #841) (#867) 2026-10-13 04:38:13 -04:00
Marco Arnulfo 7b723b7bc0 Viewport scale list: add engineering scales for imperial drawings (fixes #851) (#866) 2026-10-13 04:38:08 -04:00
aldozarandClaude Opus 5.5 a10e43cb2a CJK text: big-font cells in SHX text, CJK interface fonts in every language (#861)
Drawing (#674): in stroke-font (SHX) text, East Asian wide characters
from a fallback font fill a square cell from the baseline to the text
height, as a big font's do, instead of being scaled by the fallback
font's Latin cap height (about 1.3-1.5x too large and too widely spaced,
so CJK labels overran their space). A line no longer ends with the
stroke font's letter gap after a fallback glyph.

Interface (#513): a CJK font is installed after the Latin one in every
interface language, not only Chinese, so Japanese or Chinese file,
layout and layer names stop showing as boxes. A Japanese font comes
first unless the interface is Chinese; a craft-fonts face embedded in
the build comes last, for systems (and the web build) without one.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 04:38:03 -04:00
Marco Arnulfo 7e38081b54 Control channel: control.methods lists the methods, ping answers (fixes #843) (#852)
A client could only learn the top-level methods from docs/control-protocol.md;
help, methods, ping and the like all came back as "unknown method". The app
and the headless backend now answer control.methods with each method they
serve ({method, params, description}) and ping with "pong", and an unknown
method's error points to control.methods. A test keeps the app's list equal
to the doc table and checks every listed method is dispatched.
2026-10-13 04:37:57 -04:00
Marco Arnulfo 3f709bed2e Desktop: a bare --control keeps the CADCRAFT_CONTROL_PORT port (fixes #844) (#848)
`--control` as the last argument read `args.next()` as None and reset the
port taken from CADCRAFT_CONTROL_PORT, without logging anything, so
`CADCRAFT_CONTROL_PORT=47321 cadcraft --control` started no control
channel. A bare `--control` now keeps the variable's port and logs a
warning either way; a port given on the command line still wins. The
precedence is documented in docs/control-protocol.md.
2026-10-13 04:37:52 -04:00
Ray caad180e98 fix(dxf): MTEXT direction ignores the embedded object's insertion point (#667) (#834)
An R2018+ MTEXT can carry an embedded object (group 101) in which 10 is the
X-axis direction and 11 the insertion point. AutoCAD writes one for MTEXT with
column settings, and so does the DWG bridge. The reader took the first group 11
anywhere in the entity as the direction, so such text turned towards its own
insertion point. Read 11/21 and 50 from the MTEXT's own groups only.
2026-10-13 04:37:47 -04:00
Valentin KleinandClaude Sonnet 5.5 80ec2dcc60 Ctrl+Z / U during LINE, PLINE... removes the last segment instead of the whole command (#750) (#831)
Co-authored-by: Claude Sonnet 5.5 <[email protected]>
2026-10-13 04:37:42 -04:00
46ab40d211 Keep the layout tabs inside the status bar (#821)
* Keep the layout tabs inside the status bar

With many layouts or long layout names the tabs ran under the coordinates and
the drafting toggles and off the window.

The tabs now stop before the right-hand controls, leaving room for the
coordinates: Model and "+" stay, then the run of layouts that fits, always
holding the current one. A name wider than 150 px is cut with "…" and shows in
full on hover. When some layouts don't fit, a button after the last tab lists
them all; the "Layout list" button at the left of the bar opens the same list
(it did nothing before).

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Status bar test: expect the other layout tabs only when the bar has room

At 900 pt the layout tabs that don't fit move into the layout list (d2fe40b), so
only the current tab is painted there. The test still required "Layout2" at
every size and failed on main.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Chanthawat Kiriyadee <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 04:37:37 -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 <[email protected]>

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

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 5.5 <[email protected]>
2026-10-13 04:37:31 -04:00