Use the operating system trust store and Windows proxy settings while keeping TLS verification enabled. Add retryable registry errors with copyable diagnostics.\n\nRefs #563
Avoid full document, cache, and GPU rebuilds for entity deltas so add, delete, history, selection, and live polyline edits stay responsive on large drawings.
Replace the raw sentinel input with typed CAD lineweight options so special
values display correctly and unsupported values cannot be entered.
Refs #522
Hold edit leases and compare disk fingerprints before replacement so another editor cannot be silently overwritten.
Offer retry, reload, Save As, or explicit overwrite recovery.
Closes#498
iced's clipboard rides window_clipboard, which has no wasm backend — a
focused text_input captured Ctrl+C/V on the web and did nothing.
Ctrl+V (captured, wasm only): read the async browser clipboard (the
keypress is a user gesture, so it's permitted) and replay the text as
synthetic KeyboardEvents on the winit canvas — the only route into a
focused text_input, since iced exposes no insert-text operation.
Control characters are dropped and the length is capped. The MText and
inline-TEXT editors keep their dedicated paste paths (no double feed),
and an unfocused Ctrl+V still runs PASTECLIP.
Ctrl+C (captured, wasm only): a widget operation pairs each text_input
with its focus state (iced fires both callbacks back-to-back on the
same widget) to collect the focused field's visible text, then writes
it with navigator.clipboard.writeText. Whole-field text, not the
selection — iced doesn't expose the selected range.
Native behaviour is unchanged.
Closes#346
Co-Authored-By: Claude Fable 5 <[email protected]>
Shift+right-click in the viewport opens a cursor-anchored grid of snap
icons (names as hover tooltips). Picking one engages a one-shot
override: only that snap applies — even with running osnap off — until
the next point pick commits, which restores the saved configuration.
Esc drops an unconsumed override; an outside click closes the menu.
The status-bar snap toggles are untouched — this is a separate,
temporary mechanism.
Covers items 1 and 2 of #337 (mid-between-two-points still pending).
Co-Authored-By: Claude Fable 5 <[email protected]>
Dropping a supported file (dwg / dxf / bak / sv$, case-insensitive)
opens it through the existing open flow: an already-open drawing
switches to its tab, a load in progress queues the drop behind it
(multi-file drops arrive one event each), anything unsupported reports
on the command line instead of failing silently in the parser.
Platform support follows winit 0.30: Windows, macOS and Linux/X11
(incl. XWayland) deliver FileDropped; the Wayland backend does not
implement file drag & drop yet, so drops are inert there until winit
gains it.
Closes#344
Co-Authored-By: Claude Fable 5 <[email protected]>
Tool highlights used to stick: every click set active_tool, but only
interactive commands and a hand-maintained per-modal list ever cleared
it, so one-shots (Cleanup/AUDIT, view actions) and unlisted dialogs
(Customization/ALIASEDIT, CUI, Plugin Manager…) stayed blue forever.
Now the rule is mechanical: state toggles light from state only (the
click highlight drops immediately), interactive commands stay lit
while running, dialog openers stay lit until the modal closes (generic
clear replaces the per-modal list), and one-shots never keep it — the
dispatch site turns the highlight off when nothing stayed running.
On the Start tab, tools whose command the start gate refuses now render
dimmed (grey icon + label) across all button styles, dropdowns and the
quick-access strip; start_allowed() is the single shared authority.
Co-Authored-By: Claude Fable 5 <[email protected]>
A thin divider after the Name header resizes the column by drag
(60-640 px, session-persistent), riding the shared modal drag flow.
The name elide budget follows the column width, so widening the
column reveals long layer names; the hover tooltip stays for overflow.
Co-Authored-By: Claude Fable 5 <[email protected]>
Deleting/renaming Standard was already blocked in the five style
managers, but a file saved without the built-ins (foreign or damaged)
opened with broken style dropdowns and nothing to reference — re-seed
missing Standard text/dim/table/mleader/mline styles on every open.
Every modal dialog now shows its name in the title bar: centred at
15px across the dialog width, with the move grip and close button
overlaid at the right edge. The bar takes an explicit width from the
caller — a Fill child inside the Shrink frame would blow the dialog
out to the full screen.
Co-Authored-By: Claude Fable 5 <[email protected]>
The right-click menu was pinned to the screen's bottom-left corner.
Each layout tab now records its screen bounds through a PosReport
wrapper (which learned runtime-built ids for the dynamic tab names),
and the menu anchors next to the clicked tab via the shared
status-bar popup positioning, falling back to the left edge only when
no bounds were recorded (#428).
Co-Authored-By: Claude Fable 5 <[email protected]>
Source half of b672023 (which captured only the removed bundled
thumbnails — the add aborted on the already-staged deletions): the
videos module (playlist scan, oEmbed titles, config-dir thumbnail
cache), the boot fetch on its own thread with the loading state, the
overlay rail + Videos tab on the Start page, and the earlier tabbed-
layout handover.
Co-Authored-By: Claude Fable 5 <[email protected]>
The editor preview mis-sized imported MTEXT badly (tiny, huge, or
collapsed). Two root causes:
- The entity's base height often isn't the visible text height: relative
`\H…x;` codes compound, so an entity of height 1 whose body is `\H0.2x`
renders at 0.2. Normalize the preview scale by the DOMINANT rendered run
height (the mode of glyph-box heights, skipping zero-width caret slots),
not `height_value()`, so the body lands at a fixed readable size and
headings keep their proportions. EM_PX = 15.
- The bug that made it "completely wrong" was in the serializer, fixed in
acadrust 389b31a (\H heights decayed on the parse→serialize→parse the
editor does via folded_value); bumped here.
Also render multi-column MTEXT with its columns side by side (as the
drawing does) and let the preview scroll horizontally to reach them.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Route the MTEXT editor through the shared in-canvas modal frame with an
Apply-at-top toolbar (style-manager style): Apply commits and keeps the
editor open (creates on first apply, updates in place after), the ✕
cancels. Give every modal a bottom-right corner resize grip driven by a
shared grow-only `modal_resize` delta that resets with `modal_offset` on
open/close, so each dialog opens at its natural size and can be dragged
larger — style managers included.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Double-clicking a drawing started a whole second copy of the app. Now it
lands as a tab in the editor already open, and that window comes forward.
The election is the bind itself: every GUI launch tries a deterministic
per-user loopback port, and the OS grants it to exactly one process and
releases it on any death, SIGKILL included. Nothing to reap, no PID to
probe, no stale lock after a crash. The winner serves the port from an
iced subscription; the loser checks it is talking to a matching editor,
hands the paths over and exits. Every surprise — no answer, a stranger on
the port, a timeout — boots a normal window, i.e. the old behaviour: the
feature can degrade, but it cannot lose the file.
The gate in main is positional, after every headless mode has returned.
The plugin runner is this same binary re-spawning itself, so a flag list
would rot the first time a mode is added; a position cannot.
Handing a drawing over that is already open switches to its tab instead
of loading a second copy, comparing resolved paths so a symlink or a
`..` hop is still recognised as the same file.
`opening` is a single slot that a second open would overwrite, and
on_file_opened drops any result arriving once it is clear — so drawings
handed over at once would silently vanish. They queue in pending_opens,
drained from every path that clears the slot, error and cancel included.
Exec becomes %F so one launch takes the whole selection; the CLI takes a
list and boot fans it out through the same door. --new-instance forces a
separate process; --read-only / --script / --new always get their own.
Not reused: the automation server. It dispatches arbitrary commands and
writes arbitrary paths, and its open replaces the active tab's document
in place — publishing that on a port every local process can reach would
be unforced privilege escalation. Only its JSON-lines framing is shared.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
On native the button opens the OS save dialog (folder + name + overwrite)
and on web it starts the download, so it does not itself save — "Continue"
reads truer than "Save".
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Selecting a block and running BEDIT (command, ribbon button, or a
double-click on the block) opens a block-editor "space" tab, named after
the block, alongside Model/Layout in the status bar. The tab draws ONLY
the block record's own entities in block-local coordinates; edits are
live on the definition, so every INSERT updates. Save Block / Discard
buttons (side toolbar) finish the session; Discard restores the on-entry
snapshot. Space switching is locked while a block is open, and BEDIT and
REFEDIT are mutually exclusive.
Implementation: a Scene.block_edit_block override at the top of
current_layout_block_handle scopes render/pick/new-entity ownership to the
edited block while current_layout stays "Model" (so the pervasive
Model-vs-paper code keeps model behaviour). The model render/pick paths
that hardcoded model_space_block_handle (wire tile set, hatch render +
pick, block-instance meshes) are made binding-aware so the block isolation
actually takes effect and model content does not leak in. Entering fits
the camera to the block (fit_all already scopes via the binding). Renaming
the block tab renames the block itself — new Scene::rename_block re-keys
the record, updates the Block marker and repoints every INSERT reference.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Make objects genuinely annotative — carrying real per-scale
representations that interoperate with other CAD apps — rather than just
a native flag. `create_annotation_context` synthesizes the extension-dict
chain (AcDbContextDataManager -> ACDB_ANNOTATIONSCALES -> per-scale leaf)
from the entity's placement; the editable Annotative toggle now covers
Text and block references as well as MText/MLeader; and a new
"Annotation Object Scale" dialog (OBJECTSCALE) adds/removes an object's
per-scale memberships. Requires the acadrust ObjectContextData encoder
(Cargo.lock bump).
Also fixes a render bug where objects carrying an *empty*
ACDB_ANNOTATIONSCALES (a single-representation marker with no per-scale
reps) were treated as annotative and (mis)scaled by the annotation factor
in scaled paper viewports, ballooning the text: an object is now
annotative-by-context only when its scale collection is non-empty, so
such objects render at their base geometry.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Double-click rename did nothing and ratio edits were lost when switching
scales — and on drawings saved by other programs nothing could be edited
at all.
- Fallback scales were virtual (no Scale objects), so edit/rename no-oped;
materialize the standard set into real staged objects when the manager
opens, reverted on close unless applied.
- On third-party DWGs the mutators walked the root named-objects dict ->
ACAD_SCALELIST, which can be unreachable, and matched dictionary keys
that are internal ids (*A1, A0) rather than scale names. Locate the
scale-list dict robustly and match scales by object name + handle.
- Rename rows inline via double-click; repair a dangling current-scale
header pointer on staged rollback.
- Stage text/mleader style-manager edits on switch so they persist like
the scale manager.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Replace the scale popup's inline delete/add affordances with a single
"Manage scales..." row that opens a proper manager, matching the style
managers: it reuses the shared style-manager palette and chrome (toolbar +
list + editor frame), so it looks and behaves like the Text / Dim / MLeader
managers.
The manager lists the drawing's annotation scales (name + ratio, the current
one checked) and edits them through a Name / Paper units / Drawing units
editor: New adds a scale from the fields, Apply renames / re-ratios the
selected one, Delete removes it (never the current scale), and Set Current
makes the selected scale the model-space annotation scale. Backed by
Scene::add_scale / remove_scale / edit_scale on ACAD_SCALELIST.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Typed values were quantized to the f32 grid before reaching the
entity (e.g. a length of 2000.8 committed as 2000.8020), worsening
with magnitude. The interaction point layer was all glam::Vec3 (f32).
Two-layer fix:
1. Coordinate backbone -> f64. last_point, last_cursor_world,
dyn_anchor, dyn_ref become DVec3; UcsXform transforms, parse_coord,
the ucs helper fns, dyn_resolve_point, the OTRACK typed-distance
paths, command-line coordinate entry and the coordinate readout all
compute in f64. Screen/GPU/alignment stays f32 (snap engine, render
geometry, projection, UCS-icon/viewcube drawing) with casts only at
those boundaries.
2. Per-command committed storage -> DVec3. on_point already received a
DVec3, but many command impls narrowed it back to f32 (let pt =
pt.as_vec3(); Vec<Vec3> fields) and re-widened at build, quantizing
the committed coordinate. Migrated PLINE, SPLINE, MLINE, LENGTHEN,
INSERT, 3D primitives, every dimension/leader/mleader, ray, revcloud,
wipeout, attdef, table, tolerance, array center, mview, plot_window,
plus the QDIM_PLACE handler and qdim_collect_points. Preview,
hit-test and rubber-band paths keep f32 at the boundary.
Hatch manual boundaries are left for a follow-up: HatchModel.boundary
is structurally Arc<Vec<[f32;2]>> and needs a model-level widen.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Rewrite the in-app MTEXT editor to run on acadrust's structured
MTextDocument model end-to-end: load via parse_mtext, edit a flat Cell
model, serialize via to_mtext_string. Retires the hand-rolled format-code
string handling, the parallel visible_spans parser, the composed_value
prefix, and the Edit-raw-code tab.
Selection and copy:
- double-click selects the word, triple-click selects all (click-counting)
- Ctrl+A selects all text
- Ctrl+C copies the selected text to the clipboard
Formatting:
- per-selection Bold/Italic/Underline/Overline/Strike/Case/Alignment
- Bold renders as a visibly thicker SDF pen, keyed (family, char, bold)
through the whole text pipeline; the resolved style font name is stamped
so the \f...|b1; code survives serialization
- per-selection font and color changes
- editor color dropdown reuses the Properties panel color selector
Global toolbar defaults (font/color/oblique/width/tracking) fold onto the
document as real span properties instead of a leading code prefix; a
trailing empty paragraph is preserved so Enter at the end keeps its line.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Replace the custom in-app file-browser save dialog with the native OS
save dialog for choosing the destination path — folder browsing and
overwrite confirmation now come from the OS. A compact in-app modal
still selects the DWG/DXF format and version (a native dialog cannot
carry the version year) and appears only for Save As. Plain Save on an
unsaved drawing defaults to DWG 2018 with no picker. The file-name field
is shown only on web, where there is no native dialog.
Remove the hand-rolled directory listing, folder navigation, and
overwrite modal.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Generate a small wire-raster thumbnail when saving a DWG and embed it via
acadrust's preview API, so OCS drawings show a thumbnail in file browsers
and other CAD applications. Read the embedded preview back cheaply (file
header + preview bytes only, no full parse) to show a thumbnail per file
in the Start page's Recent Documents panel.
- io/thumbnail.rs: CPU rasterizer (current-layout wires -> BMP DIB) plus
a preview-only reader/decoder (BMP/PNG -> iced handle) for the Start
page.
- Embedded on save via stamp_thumbnail on both save paths.
- recent_thumbs cache filled on config load / recents change (never from
a view); a thumbnail is drawn beside each recent file.
Requires acadrust at 3111694 (preview read/write), already pinned in
Cargo.lock.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
The Coords pill always showed live absolute X,Y,Z, ignoring the drawing's
$COORDS (coords_mode) sysvar. Drive the readout from it:
- 0 static — the last picked point; the readout freezes between picks.
- 1 live — continuous absolute X,Y,Z (previous behavior, default).
- 2 polar — distance<angle relative to the last point while a command is
prompting for a point; absolute otherwise.
The cursor and last point are reported in the active UCS, matching the rest of
the readout. Clicking the pill cycles the mode 0→1→2→0 (CycleCoordsMode), marks
the tab dirty and echoes it; SETVAR COORDS still works. $COORDS round-trips per
drawing via acadrust's coords_mode.
Co-Authored-By: Claude Opus 4.8 <[email protected]>