Sign the bare .exe before the MSI is built (so the packed copy carries
the signature) and the linked .msi afterwards, via
azure/artifact-signing-action with SHA256 digests and Microsoft's
RFC3161 timestamp server. Credentials come from the AZURE_* repository
secrets.
Also fix the MSI version fallback: workflow_dispatch runs use the
branch name as ref_name, which is not a valid numeric ProductVersion,
so candle failed on any non-tag run.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- release.yml: ad-hoc codesign the .app before packaging so a quarantined
download avoids the "app is damaged" Gatekeeper verdict; emit the cask
version + sha256 to the job summary each release for easy tap bumps.
- packaging/homebrew: Homebrew cask + tap/usage notes; install via
--no-quarantine (the actual Gatekeeper bypass for an unsigned app).
- README: split macOS install into Homebrew and manual .dmg paths with
the xattr / Settings "Open Anyway" fallbacks.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Three polyline issues in the FILLET/CHAMFER commands:
- The polyline preview wire ignored bulge, so a filleted corner previewed
as a straight line instead of the arc. lwpoly_pts now tessellates bulge
segments via BulgeArc (same as the entity render).
- Hovering a polyline edge didn't highlight it: the first-pick hover only
handled Line/Arc. Both commands now highlight the nearest polyline
segment on hover.
- CHAMFER didn't work on polylines at all (Line-only). Added a SecondPoly
step + chamfer_lwpoly_corner: pick two adjacent segments of one polyline
to cut the shared corner back by the two distances with a straight edge.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The truck B-rep pipeline is Z-up (solids extrude/raise along Z, profile
wires convert pass-through), but two spots still assumed a Y-up world:
- REVOLVE swapped the axis/origin to (x, z, y), so the revolve axis sat
in the XZ plane while the profile sat in XY → wrong solid. Use the
axis/origin straight through.
- OBJ import kept Y-up coordinates as-is on the (now Z-up) viewport, so
imported meshes lay on their side. Rotate +90° about X on import
(positions + normals): (x, y, z) → (x, -z, y).
EXTRUDE (sweep along +Z) and the box/cylinder primitives were already
Z-up and unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The trim/extend preview wire for an LwPolyline placed each vertex at
[x, elevation, y] (the old Y-up swap), so the highlighted boundary was
drawn in the wrong plane. Use [x, y, elevation] to match the entity
render and the rest of the now-XY commands.
(The remaining axis swaps live in the 3D revolve / truck B-rep pipeline,
which is a separate, internally-consistent Y-up subsystem.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The drawing plane is world XY, but break, join, rectangular array, the
stretch/window move, the spline preview wire and several doc comments
still used the stale "Y-up XZ" mapping (world Z = DXF Y). That made
those commands operate against a constant-elevation axis: arc/circle/
line/spline break and join picked the wrong points, rectangular array
stepped rows along the Z (elevation) axis, window-stretch tested the
wrong window bound, and the spline wire drew in the wrong plane.
Map every drawing-plane coordinate through .y (elevation on .z),
matching the entity builders, the inquiry commands and the central
transform. Stale Y-up comments updated to avoid future confusion.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
These commands still read the cursor / entity coordinate with the old
"Y-up XZ" assumption (world Z = DXF Y), which is wrong now that the
drawing plane is world XY: ID/DIST/AREA reported swapped Y↔Z values and
zero-area, and fillet/align/lengthen picked against a constant-elevation
axis. Read the drawing-plane coordinate from .y (elevation stays on .z),
matching the central transform and the entity builders.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The pick/typed point is the world XY plane (z = elevation = 0), but
several entity builders still mapped the screen point as if the world
were Y-up (drawing in XZ), reading the constant elevation as the DXF Y.
That collapsed shapes onto a single line — e.g. a revision cloud always
came out as two horizontal lines regardless of the path drawn.
Map the drawing-plane point straight through (x→x, y→y, z→elevation) in:
revcloud, donut, mline, raster image, wipeout (polygonal + rectangular),
table, attribute definition, and tolerance. Previews already used the
correct pass-through, so they matched the cursor; only the committed
geometry was wrong.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
On some Windows hybrid-GPU laptops the AMD OpenGL driver (atio6axx.dll)
access-violates the instant wgpu enumerates its GL backend at startup,
killing the app before any window appears — even though DX12 works fine.
The crash is inside AMD's proprietary GL ICD, so it can't be fixed
app-side; instead default WGPU_BACKEND to dx12,vulkan on Windows so the
GL ICD is never touched. An explicit user-set WGPU_BACKEND still wins, so
GL remains available via override.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
vtkio (via truck-meshalgo → xz2 → lzma-sys) linked the system liblzma
dynamically, baking a Homebrew path (/opt/homebrew/.../liblzma.5.dylib)
into the macOS binary. The .app then crashed on launch on any Mac
without that exact library. Enable lzma-sys's `static` feature so
liblzma is compiled from the bundled source into the binary, making it
self-contained on every platform (verified: no dynamic liblzma link).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tables without a baked block (e.g. created in-app) were drawn as a single
monochrome wire, ignoring cell colours/fills/border styling. Add a
coloured synthesis path that emits per-colour WireModels for:
- cell background fill (fill_color + fill_enabled),
- per-cell text in its content/text colour,
- grid borders with per-edge type/weight/colour/visibility (cell-style
override → row-style → default),
- horizontal/vertical margins and flow direction (down/up).
Imported tables keep using AutoCAD's baked block. Resolution layers the
per-cell CellStyle over the TableStyle row style over defaults.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Picks up 5352477: STYLE/DIMSTYLE annotative now round-trips through DWG
via AcadAnnotative EED (ODA-spec encoding), matching the DXF side.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Picks up bc711f0: annotative is now persisted the standard way
(AcadAnnotative XDATA for STYLE/DIMSTYLE/TABLESTYLE, native group 296 +
DWG bit for MLEADERSTYLE), superseding the earlier non-standard marker.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Creating a new MLeader/Table/MLine style (and a new PlotSettings) pulled
the document's next handle without advancing the counter, so two records
created in one session collided on the same handle and the second
overwrote the first. Use allocate_handle(), which reserves and advances.
Also bumps acadrust to pick up DXF annotative-flag persistence.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Table Style editor now exposes every TableStyle / RowCellStyle field:
- General: description, flow direction (Down/Up dropdown).
- Per cell: data type, unit type, format string, plus all six borders
(left/right/top/bottom/horizontal-inside/vertical-inside) with line
type (Single/Double), line weight, color (ACI), double-line spacing
and a visibility toggle.
Border type/visibility apply immediately; the numeric border fields and
data/unit/format are written by the existing "Apply cell" button.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MLeader Style editor now exposes every MultiLeaderStyle field: line
weight, line type / arrowhead block / text style / block-content blocks
(handle dropdowns from the document's tables), the four text attachments
+ attachment direction, the full block-content group (color, connection,
rotation, X/Y/Z scale, enable scale/rotation), leader & multileader draw
order, align space, and description.
Dimension Style editor adds the last uncovered DIMUNIT field.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The bare STYLE command (sent by the Annotate-tab text-style combo's
"Manage…" button) fell into the LIST arm and only printed the style
list instead of opening the manager. Route no-arg STYLE / TEXTSTYLE to
the dialog, matching DIMSTYLE / TABLESTYLE / MLEADERSTYLE.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The detail-panel scrollables defaulted to shrink-to-content width, so
their vertical scrollbar landed in the middle of the panel next to the
content instead of at the window edge. Make the scrollables fill width
(and drop the dimstyle panel's right padding so the bar sits flush) in
the Dimension, Table and MLeader style editors.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The enum/handle pickers in the MLeader, Table and Dimension style
editors used "Cycle" buttons, which were awkward. Replace them with
pick_list dropdowns:
- MLeader: path type, content type, text angle, text alignment.
- Table per-cell: alignment (9 anchors).
- Dimension: arrowhead blocks (DIMBLK/1/2/LDRBLK) and ext-line linetypes
(DIMLTYPE/LTEX1/LTEX2), options resolved from block_records/line_types.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The arrowhead-block (DIMBLK/DIMBLK1/DIMBLK2/DIMLDRBLK) and ext-line
linetype (DIMLTYPE/DIMLTEX1/DIMLTEX2) Handle fields are now editable in
the Dimension Style manager. Each shows the resolved block-record /
linetype name and a Cycle button that advances through the available
records (NULL = Default arrowhead / ByBlock linetype). Edits bump
geometry so dimensions re-render with the new arrowheads/linetypes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Each row's RowCellStyle is now editable in the Table Style manager:
text style name, text height, text & fill color (ACI), background-fill
toggle, and alignment (cycle through the 9 anchor positions). Margin and
per-cell buffers load on open/select via a shared load_tablestyle_bufs;
edits write through objects.values_mut() and bump geometry so tables
using the style re-render.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New dedicated style-manager window for MultiLeaderStyle objects (the
existing mlstyle window edits MLineStyle, not multileader). Opened via
the MLEADERSTYLE command / ribbon manager entry.
Editable across Leader Format / Structure / Content sections:
- path/content/text-angle/text-alignment enums (cycle buttons)
- line & text color (ACI), arrowhead & break-gap sizes
- landing distance/gap, max points, segment angles, scale factor
- default text, text height
- enable landing/dogleg, text frame, text-always-left, annotative
New/Delete/Set-Current style management.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Table Style editor's General fields are now editable: H/V cell margins
(buffers + Apply) and title/header row-suppressed toggles, loaded from the
selected style on select. Per-cell (Data/Header/Title) text/fill/border
editing remains a follow-up.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the remaining ~40 DIMSTYLE variables across the tabs (and a new
Alternate Units tab): dim/ext line colors+lineweights, fixed-length ext
lines, separate arrow blocks, arc symbol, jog angle, text color/justify/
vertical pos/fill/direction, fit options (DIMATFIT/DIMTIX/DIMSOXD/DIMTMOVE/
DIMUPT/DIMTOFL/DIMFIT), decimal separator, rounding, zero suppression,
fraction + angular units, alternate units, and tolerance vert-just/zero
suppression. Only the arrowhead-block / extension-line-linetype Handle
references are left (they need a block/linetype picker).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The table-style details panel gains an Annotative checkbox that flips the
new TableStyle.annotative flag, rounding out annotative across the Text,
Dimension and Table style editors.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the annotative property (DsField::Annotative) to the dim-style edit
buffers, load/apply, and a checkbox on the Fit/Scale tab — consistent with
the Text Style editor's annotative toggle.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Expands the Text Style manager beyond font/width/oblique: big-font and
TrueType font fields, fixed text height, Backward / Upside-down flags, and
an Annotative toggle (applied live). Bumps acadrust for the annotative
field.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reworks MLEADER text/leader geometry and grip editing, and aligns LEADER
to MLEADER's conventions (kept as separate entities).
Text & landing (render path):
- Text is side-anchored on the leader-facing edge and reads outward; the
side, alignment and the horizontal landing are recomputed every frame
from the text grip's position relative to the leader, so moving the
arrow or the text re-mirrors the whole layout and the landing stays
attached to the text's near edge.
- Fixes#49: text was centred on the leader endpoint regardless of side.
Grips:
- Text-location grip plus an MTEXT-style triangle wrap-width grip at the
box's far edge; dragging it sets the MText wrap width.
- Multifunction grip menu restored and made functional: leader-line
vertices offer Add Leader / Remove Leader (Add grabs the new arrow so it
follows the cursor — click places, Esc removes it); the text grip offers
Move Independent (text only) and Move with Leader (translates the whole
multileader via a move-all sentinel grip).
Arrows:
- LEADER and MLEADER arrowheads now render at the same size (text height),
matching previews.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The editor overlay's anchor was only clamped to the top/left edge, so an
MTEXT placed near the right/bottom of the viewport pushed the 640px panel
(and its toolbar buttons) off-screen where they were unclickable.
Both the MText editor and the single-line TEXT editor now receive the
viewport canvas size and clamp the anchor against the right/bottom edges
too, so the whole panel stays visible and usable wherever it is opened.
Fixes#52
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Each model-space tile now carries its own visual style instead of one
global mode shared by every pane:
- ModelTile gains a `render_mode`; the active tile renders with the live
picker mode, inactive tiles keep their stored style, so changing one
tile no longer changes the others. Split inherits the source style.
- SetRenderMode writes only the active tile; switching the active tile
mirrors its style back into the tab (picker + live render).
- Persisted through the *Active VPORT entries (acadrust now round-trips
the render mode via DXF code 281 / DWG RC 281), restored on open for
both tiled and single-tile model layouts.
- Bump acadrust to pick up the VPORT render-mode field.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two paper-space rendering fixes:
- The full-canvas sheet instance no longer draws model-block hatches/
wipeouts/images. Those belong inside the floating content viewports;
rendering them on the sheet let them bleed past the viewport borders
when model coords overlapped the paper area. The sheet now draws only
the paper block's own fills plus the synthetic white printable area.
- Pan/zoom/orbit inside a double-clicked floating viewport (MSPACE) now
re-culls and re-uploads the viewport's wire set. The per-viewport wire
cache key now hashes the viewport's own view (pan + zoom + orbit), and
the active-viewport pan/zoom/orbit handlers bump camera_generation so
the GPU re-uploads. Previously the stale frustum-culled subset stayed
on the GPU, so newly-revealed lines were invisible (hatches, uploaded
as the full set, still showed) until MSPACE was exited.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pull acadrust b6834f2, which stops the DWG writer from collapsing every
duplicate *Active viewport to a single zoom-extents view. Fixes tiled
model layouts all sharing one camera after save→reopen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Switching between Model and a paper layout reset the camera to the last
saved state. The current camera was only written to the document on a
periodic tick, which may not have run since the last pan/zoom — so the
camera of the layout being left was lost. Sync it explicitly before
set_current_layout so returning restores where the user left off.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The overall "sheet" viewport now IS the paper view, so its own border
rectangle must not be drawn as an entity — filter it out of
paper_sheet_wires_arc (content viewport borders are kept).
Also update the doc comments that still referenced the removed
PaperCanvas widget / paper_canvas_wires to describe the GPU sheet path.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Paper space now renders entirely through the unified GPU shader, exactly
like model space — there is no separate 2-D canvas. The full-canvas
top-locked "sheet" viewport draws the layout's entities, hatches,
wipeouts and images; the desk is the container background and the white
printable area is a synthetic solid hatch.
- The white sheet fill uses draw_depth -2.0 (entity fills/wires are in
the signed (-1, 1) range) so it is always strictly behind every object,
with a negligible z offset (BIAS 0.001) — no far-plane clipping.
- Delete src/scene/paper_canvas.rs (the PaperCanvas widget) and its dead
helpers (paper_canvas_wires / paper_sheet_wires / paper_canvas_cache).
paper_canvas_hatches / _wipeouts remain — still used by paper hit-test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Paper space now renders its sheet through the unified shader, the same
path as model space: a full-canvas "sheet" ViewportInstance draws the
layout's own entities + viewport borders + interim/preview wires, with a
camera locked to the top/plan orientation (paper is 2-D and never
orbits). Floating content viewports overlay it.
- PaperCanvas no longer draws entity wires (still paints the desk, sheet
and hatch/wipeout/image fills; full removal is the next step).
- Right-drag on the paper sheet no longer orbits the camera (it would
corrupt the frame and skew subsequent pans).
- Fix floating-viewport orbit oscillation: orbit_active_viewport wrote
view_direction.y negated while camera_for_viewport reads it un-negated,
so each drag step read back a Y-mirrored camera and flipped the model
between a rotation and its opposite every frame. Store eye directly,
matching snap_active_viewport_to_direction and the reader.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Persist the paper-space camera through the sheet viewport entity (which
round-trips natively in both DXF and DWG) instead of the
OpenCADStudio_Camera_* named-View side-channel:
- apply_sheet_viewport_camera reads the sheet viewport entity first; the
named View is only a backward-compat fallback for older files.
- sync_camera_to_document (paper) writes the camera only to the sheet
viewport entity. Model branch is unchanged.
- Add Scene::ensure_sheet_viewport: guarantee every paper layout has its
full-screen overall (id==1) viewport, creating one if a loaded file
lacks it; wired into layout enter and add_layout.
- Restore the owner-handle guard on the sheet-viewport finder so a
foreign layout's viewport can't be picked as the sheet viewport.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Single-click selection only tested wire-edge proximity, so clicking a
solid's face missed — only its thin projected edges were selectable.
Add mesh_click_hit: project each mesh triangle to screen and test the
cursor against it (front-most wins), wired as a fallback after the wire
and hatch hit-tests. Works for any meshed solid.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rename the Home tab to "Draw" and add a Model tab beside it with two
groups:
- Model: BOX / CYLINDER / CONE / SPHERE / WEDGE / TORUS, placed with a
footprint + height. Each is built as a real ACIS Solid3D (acadrust
primitive builders) plus a truck B-rep, tessellated into the shaded
mesh pipeline, with edge wires for picking + wireframe.
- Design: UNION / SUBTRACT / INTERSECT via truck-shapeops.
A session-only Scene.model_solids cache holds each solid's truck B-rep
so the boolean tools can combine and chain them. Supersedes the old
command-line BOX/SPHERE/CYLINDER (insert::solid3d_cmds keeps EXTRUDE/
REVOLVE/SWEEP/LOFT).
Known limitations: booleans need solids created this session; curved
ACIS primitives render in-session but not after reload (the SAT
tessellator handles only planar caps); geometry assumes world_offset 0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The annotation style combo renders its panel inline with no backdrop to
catch outside clicks, so it stayed open after clicking into the viewport
or starting another tool. Close any open ribbon dropdown on viewport
press (left/right/middle) and on command dispatch.
Fixes#50
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Route every text-bearing entity to an in-place editor instead of the
command line: a plain text box for single-line text (Text, attributes,
dimension override, tolerance) and the rich MText editor for MText /
MultiLeader. A Leader resolves to the entity it annotates.
- TEXT places a plain text box at the click; double-click edits in place.
- DDEDIT and double-click on any text entity open the matching editor.
- MLEADER places the leader then opens the MText editor on its content.
- LEADER follows the classic flow: points, Enter, then a linked empty
MText annotation opens in the editor; the leader's annotation_handle
links the pair so they edit/erase as a unit.
Adds shared field read/write helpers and a begin_text_edit router, plus
CommitAndEditText / CommitManyAndEditText results that commit an entity
and open its editor (commit_entity now returns the new handle).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Type directly into the rendered MText preview: click to position the
caret, insert/delete, Enter for a new line, Space for a literal space,
and arrow keys to move. The caret blinks when idle.
Keep the trailing empty paragraph in the editor so the caret appears on a
fresh line immediately after Enter, before any typing. parse_mtext_paragraphs
split into a _ex variant; layout_mtext skips the blank-edge trim when
emitting glyph boxes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>