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]>
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]>
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]>
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.
`--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.
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.
* 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]>
* 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]>
* MLEADEREDIT, MLEADERALIGN and MLEADERCOLLECT (#812)
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
* Move MLEADER translation lines away from the end 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]>
Plain TEXT and MTEXT are picked anywhere inside their box, but a
dimension or multileader was only found near its lines: its hit geometry
is built without text. Hovering or clicking the words of a dimension found
nothing (on a survey plan, 2 of 34 letters of a dimension's text).
A point inside the box around the words, turned with the text, now picks
the object. A dimension with a block, as AutoCAD saves them, is drawn
from that block, so its text box comes from the TEXT and MTEXT in the
block, not from the text the dimension's own geometry would place (on the
same plan that was a different place, eight times smaller). A
multileader's text box comes from its MTEXT layout.
Co-authored-by: Cody Vogt <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
The view-limited path differs from full detail by ~3e-16 on Windows (float noise from the rotated-frame round trip); the test now compares structure exactly and coordinates within 1e-9.
Co-authored-by: Claude Sonnet 5.5 <[email protected]>
* BOUNDARY: cap point list and aggregate output per call (#723)
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
* BOUNDARY: a call over the output budget restores the drawing
The session does not roll back a command that returns an error, so the
polylines created before the cap was hit stayed in the drawing.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
---------
Co-authored-by: Claude Sonnet 5.5 <[email protected]>
Adds Italian as an interface language: 1,227 rows written from the
English strings with Italian desktop-CAD vocabulary (Disegna,
Tratteggio, Quota, Direttrice, layer, spazio modello/carta). Two
`menu` entries keep the menu-bar headings apart from the command and
tool-group labels: View → Visualizza (object label: Vista) and
Modify → Edita (tool group: Modifica). Italian integer plurals follow
the English rule (one, other).
Registered in i18n::LANGUAGES and Preference (code `it`), reported in
the catalog tests, with a locale/preference/plural/menu/font test;
attributed in ATTRIBUTION.md; README, ROADMAP, docs/localization.md,
docs/localization-parity.md, docs/control-protocol.md and the Options
doc comment list the language.
Co-authored-by: Claude Fable 5.1 <[email protected]>
* LINE: resolve deferred TAN first point with typed @distance<angle>
* LINE: collapse the nested if-let (clippy collapsible_if)
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]>
* Geometry: spline arc length converges on tight bends, so LENGTHEN shortens to the target (fixes#705)
* Geometry: cap adaptive spline quadrature (depth 10, 1e-10 relative) so a hostile spline can't make LENGTHEN slow
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]>
Another program's file can name a $HANDSEED below handles it uses (a DWG
read through the bridge did: its seed was under the handles of its
dimension blocks). The faces a polyface mesh becomes were numbered from the
seed while reading, so they could take handles of records further on in
other lists (another block); within one list duplicates were already
renumbered. A DWG keeps one object per handle, so saving one lost the
duplicates: 15 faces of a block's mesh in a permit set.
Before entities are read, every handle a file uses is now reserved. A file
CADCraft wrote names its own next handle (#495), above which its rebuilt
records are numbered, so it is left to that and resaves stay identical.
Co-authored-by: Claude Opus 5.5 <[email protected]>
Saving regenerated every dimension's anonymous block, even dimensions read
from another program's file and never touched: the definition points went
and other programs then showed CADCraft's drawing of each dimension (a
dimension line split around its text came back whole, for instance).
A dimension still linked to the block it was read with hasn't changed
since: every edit drops the link, and the screen draws that block while it
is there. Its block is now written as read, under its name and handles;
edited and new dimensions are generated as before.
On a 1,013-dimension permit set saved DWG -> CADCraft -> DWG, every
dimension's block now matches the original (before: none).
Co-authored-by: Claude Opus 5.5 <[email protected]>
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 <[email protected]>
A command started in one drawing kept running after a programmatic NEW or OPEN made another
drawing current. Finishing it there recorded an undo step holding the first drawing, so undo in
the new drawing brought the other drawing back. Session::new_drawing and open_drawing now end a
running command before the new drawing becomes current, as CLOSE and document.switch already do
and as starting NEW from the command line did: its undo step lands in the drawing it started in.
With no command running, nothing changes (the previous drawing keeps its selection).
The planner marked a drawing as autosaved when it dispatched the write, and the background
worker only logged a failure. An unchanged drawing whose write failed was then never written
again, even once the folder became writable. The worker now reports whether the file was
written; on a failure (or a thread that could not be spawned) the drawing is no longer counted as
autosaved, so the next plan restarts its SAVETIME clock and tries again.
* TRIM: a pick after a closed polyline's last cut keeps only the complementary run (#726)
With no cutting intersection past the pick, trim_polyline used the first cut
plus the perimeter as the end of the piece and then kept the run from the
first cut to the last cut plus a whole perimeter, so one extra circuit of the
outline stayed (a 4 x 4 square became an open polyline of length 24 instead of
8). The kept run now ends at the last cut before the pick.
* Docs: update the progress docs for this change
* Active viewport: redraw while panning and zooming inside it, without rebuilding the layout (#688)
Inside an active MSPACE viewport, middle-drag, trackpad pan and wheel or
pinch zoom change the viewport's view through set_view_quiet, which makes
no new revision. The layout's display list, which draws model space
through each viewport, was cached on (drawing, revision, zoom band), so it
kept showing the old view until a command such as ZOOM rebuilt it: the
viewport froze, or appeared to ignore the zoom.
The active viewport's contents are now drawn apart from the layout's list,
the way model space itself is drawn. They are built once for an area
around the viewport (half its larger side of margin all round), then moved
and scaled to the current view on the GPU and drawn under the layout's own
objects. They are rebuilt when the drawing changes, when the zoom has
moved 2x from the view they were built for, when the view leaves the built
area, and once a zoom comes to rest, so dash lengths and curve detail
follow the viewport's scale again. A pan step takes about 1 ms with 70,000
polylines, where rebuilding the layout takes about 140 ms per frame.
Rectangular viewports are clipped with the scissor rectangle. A clipped
viewport's outline is drawn into a stencil buffer as a triangle fan that
flips a bit (even-odd, as the outline clips on the CPU), and its contents
draw only where the bit is set; the native window now asks eframe for an
8-bit stencil buffer, and every canvas pipeline names its format. Where
there is no stencil buffer (the CPU canvas, the web runner), a clipped
viewport's contents stay in the layout's list, whose cache now follows the
viewport's view.
Render: Options::skip_viewport leaves a viewport's contents out of a
layout, and viewport_content builds them for any area. Viewport contents
are built on all cores, like model space (130 ms to 37 ms for 70,000
polylines).
* Active viewport highlight: selection on the GPU, hover cached apart, kept inside a clipped outline
Inside an active MSPACE viewport the selection highlight was drawn as
dashed egui shapes on the CPU every frame, about 8-13 ms per frame with
7,000 polylines selected, and its geometry was cached together with the
hover, so moving the cursor over objects tessellated the whole selection
again. The selection and the hover are now cached apart, and the
selection goes through the GPU highlight path model space already uses:
about 0.1 ms per frame. In a clipped viewport it is kept inside the
outline with the stencil mask its contents use; before, it was only cut
to the outline's bounding rectangle.
The Model layout was written with the default page setup, whose "layout"
plot area is plot type 5, "Layout information" (DXF Reference, PLOTSETTINGS
group 74). That means nothing for model space: opened in AutoCAD 2027, a
drawing saved by CADCraft had a blank "What to plot", no preview and no scale
in the Plot dialog for Model. Model space now gets what PLOT does for it: the
drawing extents scaled to fit (74 = 1, 75 = 0). DWG saves go through the same
writer; the reader already ignores the Model layout's plot settings.
Co-authored-by: EP995LAB <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
With a view, each span of a pattern line was cut to the view's extent
intersected with the boundary's. Spans already lie within the boundary,
and the boundary extent comes from rotating the corners directly while a
span end comes from interpolating along an edge, so where a line passes
through a corner the two differ by a rounding error and the cut moved the
end (by 3e-16 on Windows, whose sin/cos round differently). The spans are
now cut to the view's extent only, so normal_zoom_pattern_is_unchanged
holds on every platform.
MCP clients start their servers when they start, usually before CADCraft is
open, and `--connect` refuses to start then. `--lazy` starts the bridge
anyway and reaches the app at the first tool call; until the app answers,
each call fails with how to open it. `--launch` (implies --lazy) opens
CADCraft on macOS with that control port at a call that finds nothing, and
waits up to 30 s. Neither falls back to a headless session (#103).
Co-authored-by: Claude Opus 5.5 <[email protected]>
* HATCH/GRADIENT: points and objects in one call; GRADIENT name and centered
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* HATCHEDIT: gradient parameter (make or change a gradient fill)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* HATCHPICK: pick hatch boundaries, an origin or hatches for the dialog
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Hatch dialog: state, defaults and the OK command call
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Hatch dialog: pick points, objects, origin or hatch and come back
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Hatch and Gradient dialog window (pattern swatches, gradient, origin, boundaries, options)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* HATCH, GRADIENT and HATCHEDIT open the hatch dialog; double-click a hatch to edit; HPDLGMODE
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Hatch dialog: keep the window to its content (OK and Cancel stayed off screen); double-click test
A vertical separator between the two columns took the height available, so the window grew
every frame until its buttons left the screen. Found in the running app.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Docs: hatch dialogs in gaps, target-app parity and UI parity
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Hatch dialog review fixes
- Double-clicking a hatch at its centre opened the dialog and also started a grip edit.
- Edit mode no longer clamps an out-of-range scale or angle into a change nobody made.
- HPORIGINMODE outside 1-5 means the current origin, as HATCH reads it.
- Picks made in one space are dropped when the dialog comes back in another (layout tab).
- A gradient hatch's Pattern tab offers the current pattern (HPNAME), not SOLID.
- Ukrainian: "Default to boundary extents" said "outside the boundary".
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: lloyd <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>