CHPROP's JSON form is properties.set, so its description now names the
REFEDIT working set too and lists `message` in the result.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With every object on a locked layer, properties.set returned before it
checked the linetype, the dimension style and the dimension overrides, so
it accepted bad values there. They're now checked first, reading the
drawing without writing to it; the drawing is taken for writing, and a new
layer made, only when there are objects to change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Properties palette, Quick Properties and CHPROP's JSON form all edit
through properties.set, which changed objects on locked layers. It now
leaves them out and changes the rest, as CHPROP, MATCHPROP, MOVE and
CUTCLIP already do. During REFEDIT, objects outside the working set are
left out too, instead of the whole edit being refused.
The result gains `locked`, and a `message`, which app.run shows at the
command line, says how many were left out. When every object is left out,
the drawing doesn't change and no undo step is added.
CHPROP's JSON form was properties.set on the unlocked objects; it is now
properties.set itself.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Window opens centred; the Chinese menus have no English entries left (#1129)
The main window opened where the system cascades new windows, off to the
top-left on wide screens; it now opens centred. 26 menu and command
labels the Simplified Chinese update missed (Multileader > Collect,
Block Editor, dynamic blocks, Express Tools, Customize, ...) are
translated, and a test keeps every menu, command, tool and snap label
translated in Chinese. The start page question in the issue is left to
the owner.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* File > Open Recent's Clear Recent Files is translated in Chinese (#1129)
The Open Recent submenu is built at run time, so the Chinese completeness
test never saw its labels, and Clear Recent Files showed in English. The
label is now menus::CLEAR_RECENT, the test collects it with OPEN_RECENT,
and zh.tsv translates it. The other runtime-built menu labels (context
and tab menus) are all in zh.tsv already.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n(zh): translate Change and Units, which landed after this branch (#1129)
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
* Add -ARRAY, the classic command-line array, as AutoCAD lays it out
Rectangular arrays move the copy in row r and column c by (c * column distance, r * row
distance), asking for a distance only when there is more than one row or column; polar arrays
space n items 360/n apart around a full circle and fill/(n - 1) otherwise, turning the copies or
moving them with the group 10 point of the object selected last. The copies are separate
objects; the type asked defaults to the one used last.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* -ARRAY: refuse an unknown type and oversized arrays before making transforms
The JSON form errors on a type other than rectangular or polar, and checks MAXARRAY before the
copies' transforms are made; the command line bounds the columns by the rows (CodeRabbit).
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>
* Turkish catalog: fix wrong registers and resolve term collisions
Proofreading by a native speaker. 32 rows, wording only:
- From/To were e-mail words (Kimden/Kime) -> Kaynak/Hedef
- ViewCube Home was Giris (login) -> Baslangic
- untranslated "or" in the zoom scale prompt -> veya
- BREAK vs Cut both "Kes" -> BREAK family uses "Kir"
- TRIM vs CLIP both "Kirp" -> TRIM uses "Buda"
- spline vs curve both "egri" -> spline stays "spline"
- plot style/preview/window said "Cizim X" (= drawing) -> "Cizdirme X"
- Elevation vs Height both "Yukseklik" -> Elevation is "Kot"
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Add GULERTOLGA to contributors
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Add Vietnamese (vi) to the interface languages
vi.tsv covers every key of the other catalogs and the three strings none of them has yet, with
one plural form. Its tone-marked letters (U+1EA0-U+1EF9) aren't in egui's bundled faces, so the
Vietnamese interface takes the first system interface font that has them (Segoe UI, Arial, SF,
DejaVu Sans, Noto Sans) and otherwise stays English and says why, as Korean does without Hangul.
AI-assisted; native-speaker review pending.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Vietnamese: the terminology Vietnamese AutoCAD users speak
Polyline, Pan, Offset, Spline and Grip stay in English as they are said in the office; Modify
is Hiệu chỉnh, LINE draws an Đoạn thẳng, Explode is Phân rã, Linetype Loại nét, the plot style
table Bảng nét in, Polar and Object Snap Tracking Dò theo góc / Dò theo điểm bắt, Settings Cài
đặt; the snap modes Endpoint, Midpoint and Nearest are Đầu mút, Điểm giữa and Điểm gần nhất.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Vietnamese: name the language by the font loaded; Arabic's own message
The picker writes Tiếng Việt only when the interface's loaded system font has its letters
(another interface loads the first installed candidate, which may lack them). The font choice is
one function with a unit test, gated off wasm with its callers. Choosing Arabic without an
Arabic font no longer gets the Chinese message.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Add CHANGE, changing objects by a change point or their properties as AutoCAD does
A change point moves each line's nearer end to it (level or plumb under ORTHOMODE), passes a
circle through it, and places a text, attribute definition or block reference by it when that is
the one object selected; otherwise "Change point ignored" and the object's questions follow, in
selection order. Properties is CHPROP's loop with Elev, applied as the command ends. Objects on
locked layers are left out, through selection helpers now shared with CHPROP.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* CHANGE: refuse a JSON call without a readable point or elevation
A `point` or `elevation` that can't be read is an error, and so is a call with neither, instead
of changing nothing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* CHANGE: Elev on every kind AutoCAD sets it for; Aligned and Fit text; rotation default
Measured in AutoCAD 2024: Elev also sets the z of ellipses, multiline texts, solids and flat
3D polylines (a 3D polyline between heights keeps them), and of hatches, which stop being
associative ("Hatch boundary associativity removed."). Aligned text isn't asked its height or
rotation and Fit text its rotation, their two points setting them. The rotation default shows
as the drawing measures angles (ANGBASE 90 shows a text at 0 as 270.00). Shared z is compared
to rounding, and the radius and height prompts say what they need.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* -INSERT: ATTREQ, Preset and Verify attributes as AutoCAD asks them
ATTREQ 0 inserts blocks with their attributes' default values without asking (a session
setting, as AutoCAD keeps it in the registry). Preset attributes are never asked for, "Enter
attribute values" heads the questions, and Verify attributes are asked again after "Verify
attribute values", each with the value typed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* -INSERT: a click doesn't answer a Verify attribute
Only typed text or Enter answers "Verify attribute values"; anything else asks again (CodeRabbit).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
RECTANG's polyline now starts at the first corner and runs along X to
the other corner, as AutoCAD 2024 draws it; each chamfer cuts the edge
into its corner by the first distance and the edge out by the second,
and fillet arcs start on the edge into their corner (clockwise outlines
get negative bulges). RECTANG keeps its chamfer, fillet, width,
elevation, thickness and rotation for the next rectangle, lists them as
"Current rectangle modes:" and offers the rotation as "<50.50>"; chamfer
and fillet clear each other. A circumscribed POLYGON starts at the end
of the picked edge counter-clockwise from its midpoint.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
AutoCAD 2024's SCALE is a uniform 3D scale about the base point: every Z
and elevation scales about the base point's Z (the current ELEVATION for a
point given without one) and every thickness by the factor. cadcraft
scaled X and Y only. The JSON form also takes a Z with the base point.
OFFSET's copy now keeps the source's height: a line's end Zs, a circle's
or arc's centre Z, a polyline's elevation. A circle's or arc's copy has no
thickness and a polyline's keeps it, as AutoCAD makes them.
Grip scaling, ALIGN's scale option and MOCORO stay 2D: their base point is
often a grip or snapped point whose Z cadcraft doesn't keep.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Add -UNITS; show due surveyor bearings as one letter
-UNITS asks for the length format and precision, the angle format and
precision, the direction of angle 0 and whether angles turn clockwise,
with AutoCAD 2024's prompts, listings, defaults and messages. As in
AutoCAD, each answer is kept as it is given, and choosing another format
resets its precision to 4. The direction is typed in the chosen angle
format and turns as ANGDIR says.
Surveyor's units show a bearing that is due north, south, east or west as
that letter ("E"), except to whole degrees ("N 90d E"), as AutoCAD's
ANGTOS does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* units: read a due bearing typed as one letter (E, N, W, S) in surveyor's units
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>
* Refuse mirror lines whose points are closer than the geometry EPS
Found while testing crates/engine/src/cmd/modify/transform.rs:run_mirror (coincidence check `a.near(b, 1e-12)`), with crates/geom/src/mat.rs:43-47 (Mat3::mirror)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* mirror: the interactive prompt also refuses points closer than the geometry EPS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Found while testing crates/engine/src/sysvars.rs:~404-425 (generic fallthrough in set: String branch, then the `Some(HVal::Real(_))` arm)
Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
Found while testing crates/engine/src/cmd/utility/calc.rs:~355-360 (call, "min" | "max" branch using f64::min/f64::max)
Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
* wblock: write the source drawing's $INSUNITS and $MEASUREMENT
run_wblock built the written drawing from Drawing::new_imperial() and
never copied the source's units, so every WBLOCK file declared inches
($INSUNITS 1) and imperial measurement ($MEASUREMENT 0) whatever the
source: a block written from a metric drawing came back at 0.0254 of
its size in any program that honours $INSUNITS on insert. The written
drawing now takes the source's values for both variables, as AutoCAD's
-WBLOCK does. A unitless source ($INSUNITS 0, kept by the reader per
#1209) writes unitless.
Co-Authored-By: GLM-5.3 <noreply@z.ai>
* wblock: start from the source drawing's header and styles
Clone the source header (resetting $INSBASE as before) and copy the
multileader, table and multiline styles and the annotation scale list
along with the other tables, so a block written from a metric drawing
keeps its text size, current dimension style, limits and scales, not
the imperial template's (review on #2023).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* wblock_units: each WBLOCK call writes into its own TempDir
The two tests shared one temp path and raced when cargo ran them in
parallel (review on #2023).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: GLM-5.3 <noreply@z.ai>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ui): dash only the visible part of a highlight, so zooming far in doesn't freeze (#2299)
With the pointer on an object, its rollover highlight is dashed, and draw_highlight dashed the
object's whole outline in screen space, off-screen parts included: one shape per 10 points of
it. Zoomed far in, a short line is billions of points long, so the app froze and then ran out
of memory, which is the freeze and crash #2299 reports. Wheel-zooming a circle and two lines
with the pointer on them reached 7.9 million shapes in one frame at a view height of 0.001
before a 1 GB allocation failed.
The highlight now clips each outline to the view, plus a margin, in world coordinates first
(precise when zoomed far in), and dashes only what is left. Each visible piece starts its dash
pattern at its distance along the whole outline, so dashes don't crawl along a line that runs
off screen while the view pans. The two dashed rectangles drawn in screen space, a layout's
printable area and the crossing window, clip each edge to the painter's clip rect for the same
reason. The same zoom now stays under 1,300 shapes per frame down to the zoom limit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ui): a clipped rectangle edge keeps its dashes where the whole edge puts them
dashed_rect clipped each edge to the screen and then started its dashes at the clip boundary,
so a printable area or crossing window running off screen had its dashes move with the view,
and its bottom and left edges were drawn in reverse. Each edge now keeps its direction and its
dashes start at their distance along the whole edge, as the highlight's outlines do. The
zoomed-far-in app test also checks that the line really is hovered, so it can't pass with no
highlight drawn.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: austin62jake <340374338+austin62jake@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
rstar 0.13 can panic when inserting after removals in a bulk-loaded tree, and picking runs outside the command guard. The patch now runs on a copy under catch_unwind and falls back to a bulk load. The web build can't catch a panic, so it always bulk-loads. Diagnosis, reproduction and fix from #2468.
Fixes#2468
Co-authored-by: octopoulpos <32617732+octopoulpos@users.noreply.github.com>
plan.dwg and plan.dxf in one folder shared plan.bak. A DWG keeps <name>.bak, as AutoCAD names it, and any other drawing appends .bak. The naming comes from #1006.
Co-authored-by: Filippo Reimer <49290121+filforce95@users.noreply.github.com>
* Validate new linetype names in the rename command
Found while testing crates/engine/src/cmd/props.rs:1154-1200 (run_rename, "linetype" branch)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* rename: a linetype's new name is stored trimmed, as -RENAME types it (CodeRabbit)
---------
Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Since #2518 the write syncs the folder after the rename, so the autosave
file exists while the write is still running. Until it finishes the drawing
is busy and the next change isn't planned, so the test's tick() returned
None. Autosaver::writing() says whether a write is still running.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(dxf): add deterministic codec and drawing round-trip matrices
Exercise typed tags and model-space LINE/CIRCLE/TEXT through in-memory ASCII and binary DXF at every save version. Compare both reads with the original model and check independent handwritten byte/entity fixtures. Keep desired-behaviour tests for extrusion and ByBlock plot-style loss explicitly ignored until fixed. No production or docs changes.
* test(dxf): independently verify common entity properties
* test(io): add a broad DWG preservation matrix with focused pending regressions
Share deterministic Drawing cases and exact assertions between DXF and DWG without reducing DXF coverage. Run representable DWG cases at all six save versions, twice in RAM. Test R2000 color/transparency and the single TEXT elevation as explicit format limits. Keep six independently reproduced loss regressions ignored without weakening comparisons. No production or docs changes.
* test(io): close binary-width and referenced-linetype coverage gaps
Check every integer group range against independently constructed binary payloads, catching shared reader/writer width mistakes. Resolve linetypes with Drawing lookup and compare layer linetypes too. Add missing/changed-reference self-tests and inherited-pattern DXF/DWG round trips. Reproduced the review counterexamples before and after; full CI passes with two nextest threads. Test-only changes.
* test(io): expand DXF and DWG matrices across entities and drawing collections
Add basic coverage for all 29 modeled entity kinds, block graphs and attributes, all ACI colors, richer properties/XDATA, sparse handles, headers, symbol tables, views, groups, layouts and foreign payloads. Preserve typed fields and authored references through two RAM saves. Add independent DXF groups and native DWG bridge checks, plus explicit refusal-or-preservation tests for unknown entities. Keep confirmed discrepancies and unresolved preservation contracts as focused ignored tests; native linetype angles and silently dropped unknown DWG entities are independently reproduced. Version limits and foreign object handle remapping are explicit contracts, not blanket normalization. Tests only; no production or docs changes. Full CI passes with two nextest threads: 2777 passed, 27 skipped.
* test(io): cover bounded property domains and targeted field interactions
Independently check all ACI values and transparency percentages, native
layer/style flag combinations, and literal large handles. Add shared DXF/DWG
cases for alignment with mirrored styles, inherited versus explicit zero
properties, repeated nested attributes, and integer-boundary handles.
Keep exhausted handle allocation separate: DWG refuses the save; a focused
ignored DXF regression reproduces silent loss of all nine model entities.
No production or documentation changes.
Validation: full cargo xtask ci with NEXTEST_TEST_THREADS=2 passes all seven
gates (2792 passed, 28 skipped). The pending DXF regression fails explicitly
when run with --ignored.
* test(dxf): separate chunk conformance from binary reader tolerance
Address PR #2237 review: shared exact-tag round trips only use hex chunks
within the documented 127-byte group limit. Independently inspect ASCII
and binary writer bytes, reassemble payloads, and verify following-record
framing. Keep full 0..255 length-byte read tolerance in handwritten fixtures,
not as a claim of conforming writer output.
Add two focused ignored regressions for oversized ASCII/binary output,
reproduced with 128-byte payloads. They extend existing issue #1025.
No production changes.
Validation: cargo xtask ci passes all seven gates with nextest 0.9.150
and two test threads (2782 passed, 30 skipped). Both new pending checks
fail explicitly when run with --ignored.
* test(io): compare DWG dimension blocks through their references
Anonymous dimension-block suffixes may change between drawing sessions (Autodesk documentation; ODA DWG section 20.4.52.1). Resolve their names through preserved dimension identities and keep strict checks for cache content, entity handles, block properties and reference integrity.
Enable the pending dimensions test across all six DWG versions and two saves. Add a paired-cache fixture and comparator controls rejecting swapped/merged/dangling references, geometry and property changes, stale caches, and named-block renaming. Leave the shared comparator and DXF contract unchanged.
Validation: cargo xtask ci (all seven stages; 2786 passed, 29 skipped); roundtrip matrix (211 passed, 26 ignored).
Resolves the preservation-contract decision in #2257 (tracker #2238, B4); no production codec fix.
* test(io): specify WIPEOUT explicit closure on roundtrip
An implicit WIPEOUT boundary gains one explicit closing marker in DXF/DWG. Compare against independently authored explicit boundaries in both winding directions across all six versions and two saves; retain strict field and resave comparisons. Enable the two pending closure checks without changing the shared comparator.
Distinguish this valid file representation from the grip-edit defect: the latter is fixed separately in PR #2284, with engine, outline and rendering regressions. No production change in this test-only branch.
Validation: cargo xtask ci, all seven stages passed (2788 passed, 27 skipped); active roundtrip matrix 213 passed; remaining ignored checks reproduce 24 drawing failures and two codec failures. One unrelated HTTP control-server test failed transiently, then passed in isolation and in the full rerun.
Related #2256 and tracker #2238 B3.
* test(io): expose multiline ATTRIB alignment corruption
Keep the original origin witness and add distinct nonzero TEXT/MTEXT anchors. An active R2018 ASCII/binary two-save check verifies world-space multiline geometry and value edits; this does not excuse corrupted fallback TEXT fields.
Retain the strict pending #2255 check and add comparison of independently downgraded R2000/R2004 geometry. The observed Left -> Center change is a real reader error, not permitted alignment-point canonicalization. The reader hunk from existing PR #1942 makes the extended strict check pass in an isolated experiment; no competing production fix is included here.
Validation of this test-only tree: all seven cargo xtask ci stages pass (2789 passed, 27 skipped); active matrix 214 passed; remaining 24 drawing and two codec diagnostics still fail. An unrelated HTTP control-server test failed transiently, then passed alone and in the complete rerun.
Related #2255, #1942 and tracker #2238 B2.
* test(io): separate ATTRIB value and legacy-placement guarantees
Assert exact saved ATTRIB values, read_as and authored embedded MTEXT contents before and after value edits. A mutation test rejects corrupt fields, including a value/read_as pair whose rendered geometry remains unchanged.
Make legacy placement an independently runnable pending regression instead of a callback behind the failing field comparator. Compare direct R2000/R2004 exports with exports after one/two R2018 roundtrips, both encodings in each stage, and verify that the primary single-line fallback actually survives. Keep all three contracts local and distinct; remove the old cross-module callback.
The new legacy test fails directly on world-space geometry with the unchanged reader. Both pending ATTRIB tests pass with the reader hunk from existing PR #1942 in an isolated experiment (548 IO tests also pass). No production fix is included.
Validation: all seven cargo xtask ci stages pass with NEXTEST_TEST_THREADS=1 (2790 passed, 28 skipped). Earlier parallel runs and one isolated retry hit pre-existing HTTP/busy control-server failures; no exclusions or test changes. Active matrix 215 passed; all 25 drawing and two codec pending diagnostics still fail.
Addresses review of #2237; related #2255, #1942 and tracker #2238 B2.
---------
Co-authored-by: cloudj <jonbahnes@gmail.com>