- Invalid Area "Undo" reverts the step that lost the boundary (redo after
an undo, undo otherwise), checks the boundary is back and otherwise puts
the step back and continues without the area; no auto-undo loop.
- COUNTCLOSE / area replacement remove the count polyline outside the
history instead of as an undo step of their own.
- UPDATEFIELD re-evaluates the field texts of a table's *T block and
reports the number actually updated.
- Zoom to a counted object goes through the f64 handle_zoom_to_window.
- Palette: SVG icons instead of glyph text, list cache keyed by tab id,
cached result borrowed instead of cloned, "Count" as the source text.
- Command-line messages go through t!/tf! with entries in all locales.
- Cleanups: \n escapes, area comment, unused parameter, comment order.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- `.dst` read/write go through native-only helpers (a browser answers
"Not available"); the folder pickers are web no-ops; time stamps use
iced::time (web-safe).
- Lock files are written only for drawings that are sheets of an open set,
released when the last set closes, and a lock a crashed session left
(recorded with its process id, same user and machine) is taken back.
The `.dwl2` header is well-formed and the date line comes from the OS
long date on every platform. The 1 Hz poll runs only while a set is open.
- Refreshing sheet set fields never stores `####`: fields no open set
resolves keep their value, and only the hosts that changed are redrawn
(and their tab marked modified).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The row menu is a small overlay widget: a click on a submenu entry opens
its fly-out instead of closing the menu, and the fly-out is placed beside
the menu where it actually landed (right when it fits, otherwise left), so
the menu never moves.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Row menus open Set category / Place Callout Block as fly-out submenus
(hover or right press; leftwards when the palette is docked right).
- List of Blocks and Select Block show the Blocks palette's preview.
- VIEW SAVE keeps the window's width/height ratio.
- Placing view content in model space is refused with the reference message.
- Drawings read for views, placement and blocks are cached by modification time.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- When the count area's boundary is gone the approved Invalid Area dialog
asks: undo the change (also its X and Cancel) or count all of model space;
"always" keeps the choice in the settings. An edited boundary moves the area.
- A table's *T block is brought up to date whenever the table changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model Views lists named model views and places them on the current sheet
(xref, viewport, paper-space named view, view label with navigation
fields, sheet view record); sheet view rows get Display, Rename & Renumber
View, Set category, Place Callout Block and Place View Label Block; the
View Category dialog's Add Blocks opens List of Blocks / Select Block; a
sheet whose relative path is gone shows missing; sheet set fields store
their values when a set changes; named views keep their centre relative to
the target. Codec pin moves to the revision with these field helpers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Import Layouts as Sheets shows the reference's statuses (already part of
a sheet set / may belong to another sheet set / available) and Browse
replaces the list; the Field dialog SheetView tree lists sheet views with
their properties, scale formats and hyperlinks; drawings open in tabs get
.dwl/.dwl2 lock files that other instances read as open; the codec pin
moves to the revision with sheet views and the default output folder.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Remove Sheets confirmation, Open in drawing editor, Select Layout as Sheet
Template for subsets that prompt, Import Layouts as Sheets with status and
prefix, Rename & Renumber options with Previous/Next and real layout/file
renames, New Subset folder hierarchy and publish setting, subset properties
rows as the reference shows them, sheet status badges (SSMSHEETSTATUS /
SSMPOLLTIME), Sheet Views by category with the View Category dialog, Model
Views locations, Field dialog SheetSet/SheetView navigation, and .dwt/.dws
read as DWG.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- COUNTCOLOR / COUNTERRORCOLOR / COUNTSERVICE reject any other value with
the range message; COUNTTABLE ? lists in the reference order, padded,
22 lines a page with Press ENTER to continue:, then the totals.
- Target picks report N found / N found, M total; several objects (or one
that is not a block reference) count their copies, shown as Geometries
in the palette.
- Current area is the area in use (kept aside by Entire model space),
otherwise all of model space; an invalid Object boundary ends with the
reference message.
- Count colours reach solids and fills; the palette list and the count
are recomputed only when the drawing changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tree menus follow the reference per row kind (New Sheet / Import on a
sheet work on its subset, Remove Subset only while empty, Rename Subset),
a new sheet is not opened, an open set reloads when its .dst changes on
disk, ViewportScale placeholders take the version of their format and
the codec pin moves to the revision with navigation fields.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The PR pinned the codec to its fork through [patch]; codec #75 is merged
upstream and main already points at it, so the patch section is dropped.
The two windows-sys features it adds (Globalization, Identity) stay.
The exponential camera step is the right call. `0.9 ^ delta` is strictly
positive for every real delta, in and out cancel exactly where the
subtraction lost a percent of the view on every round trip, and the file's
own header has promised an "exponential feel" since it was written. Three
surfaces were left behind it, and the wider range exposed a fourth thing.
The range of the system variable. 3 to 100 is the range ZOOMFACTOR has, and
the User Preferences page was built against it; `SETVAR ZOOMFACTOR` accepts
that and nothing else again. A faster wheel is the Options window's business
instead: the slider covers the variable's own range, the field beside it
reaches 500, and a read-out says what a notch actually does ("10.0% a
notch") so the number being set is readable rather than implied. A value
above 100 therefore lives only in this application's own configuration file,
where it is nobody else's to read, and a bare `SETVAR ZOOMFACTOR` still
reports it. The bounds and the clamp live in one place now
(`settings::clamp_zoom_factor`): four literal copies of `3, 100` are what
let a surface be missed in the first place.
A floating viewport in MSPACE. It zooms its own view through
`zoom_active_viewport`, which kept subtracting: the factor reached zero at
6.67 steps, so from ZOOMFACTOR 360 up every notch inside a viewport bottomed
out on the clamp — a tenfold jump a notch, and the top third of the slider
doing nothing at all. Exponential there too, from a base of 0.85 so the
default notch still moves a viewport the 15% it always has. Each surface
keeps its own long-standing feel rather than inheriting the other's.
The trackpad pinch. `pinch_zoom_steps` was calibrated against the
subtraction (`1 - step / 10 = 1 / (1 + m)`) so that a pinch of m leaves the
view exactly 1 + m times closer — the property docs/trackpad.md documents
and the reason the gesture tracks the fingers at all. Inverting the zoom law
by hand is what let the two drift apart, so the step is asked of the camera
now (`Camera::zoom_steps_for_ratio`), which cannot drift by construction.
`pinch_is_one_to_one` recomputed the old formula rather than the camera's,
so it kept passing through all of this; it zooms a real camera and measures
the distance it lands at instead.
Also: `zoom` had a floor and no ceiling, and zooming out multiplies. At
ZOOMFACTOR 500 a notch out is x2.4, so about ninety notches — a couple of
seconds of scrolling — ran the distance past what an f32 far plane
(`distance * 1000`) can hold, and the viewport went black on an infinite
projection. A degenerate pinch magnification of -1 or beyond reached the
same place through the other side. Both are bounded now.
Also: two doc comments quoted the linear law (`zoom_view_at_cursor` and the
one on `pinch_zoom_steps`), and docs/trackpad.md stated the pinch identity
and claimed the tests covered it against the camera. All updated, with what
a notch does and where each surface's range comes from written down.
Tests, each confirmed against the behaviour it describes: the zoom law at
every factor the application can hold (positive, monotonic in the setting,
in and out cancelling), the ceiling under a long scroll out in both
projections, the published inverse and what it does with a nonsense ratio,
the viewport factor and a real viewport zoomed three notches at the top of
the range, the SETVAR range including a value the Options field set, the
Options field (above 100, above the ceiling, cleared, not a number), its
agreement with the slider, Close putting both the value and the field back,
and the read-out's percentages. 1882 lib tests pass.
The two new Options strings are not in the locale catalog yet, so they
render in English until it is regenerated.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Conflicts with #1573: the locale files and the catalog take both PRs'
entries (one "Insertion Point" mapping kept); the Home and Insert Block
panels take #1574's layout with #1573's Insert Block gallery.
A Field dialog with the fields the application evaluates and the
reference format choices, FIELD placing a field as multi-line text, the
attribute definition dialogs' field buttons, field attachment on commit,
system variable / file size / regional date providers for field
evaluation, and the codec patch with the field authoring API.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two viewport-navigation defects, both measured against commercial solutions.
The cursor stayed a hand during a zoom. `selection_overlay` took one boolean
for all three interactive navigation tools, so ZOOM Dynamic and ORBIT both
showed PAN's grab hand — which reads as "drag the sheet", the wrong promise
for either. Split it into a `NavCursor` enum: PAN keeps the open/closed hand,
ORBIT gets four-way arrows, and ZOOM Dynamic gets the magnifier carrying the
sign of the zoom actually under way — "+" dragging up, "-" dragging down,
latched with a 2 px dead zone so a hand held still cannot strobe the glyph.
ZOOM Dynamic also reused `box_anchor` to remember where a drag began, so a
selection marquee rubber-banded across the screen while the view zoomed; the
drawing is now suppressed, the state left alone for `reproject_box_anchor`.
ZOOM EXTENTS did not reach the whole drawing, for three separate reasons, now
answered by one shared `Scene::visible_block_bounds`:
- A quartile filter dropped any wire whose centroid sat outside the
inter-quartile consensus of the others. It was meant to stop one junk wire
from a bad parse poisoning the box, but it could not tell parser junk from
an outlying detail, a survey point, or a block placed away from the rest,
and silently refused to frame them. Gone; the absolute 1e16 sentinel gate
the paper path already used is the only filter, and the XLine / Ray display
segments that motivated the heuristic are handled explicitly.
- HATCH tessellates to no wires at all, and the model path never read the
fill models, so a drawing whose outermost geometry is a fill — or which is
nothing but fills — had nothing to frame. It now folds them in, reusing the
renderer's own warm cache on the hot path rather than re-exploding every
INSERT per ZOOM EXTENTS.
- Inside a floating viewport the fit came from `compute_model_space_extents`,
which walked only `key_vertices` — empty for every tessellated curve.
Circles, arcs, ellipses and splines contributed nothing. Fixing it also
corrects plot Extents, sheet-set framing, viewport auto-fit and SpaceMouse
model bounds, which all inherited that blind spot.
Bounds stay f64 into the camera: a UTM drawing lost whole metres to the old
f32 round-trip. Drawing extents also no longer read the camera — the result is
cached per geometry epoch, and a floating viewport's camera is derived FROM
the extents, so `camera_for_viewport` recursed into a stack overflow.
`model_space_extents_mixed_entities_accuracy` asserted the curve-blind result;
it now asserts the true bounds.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Attribute Definition dialog and Edit Attribute Definition dialog, -ATTDEF
with the reference prompts and modes (AFLAGS), tag shown in the drawing,
justification-aware grips, reworked Properties with validation, Home Block
slide-out and Insert Block Definition panel, and the codec patch for
ATTDEF DXF output and the R2013+ solid wire cache.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebuild the Blocks palette with Current Drawing / Recent / Favorites /
Libraries tabs, wildcard filter, six views, insertion options, click and
drop insertion and a block context menu. INSERT opens the palette, the
new -INSERT runs on the command line, the ribbon Insert button becomes a
block gallery, and BLOCKMRULIST, BLOCKREDEFINEMODE, BLOCKNAVIGATE,
BLOCKSTATE, EXPLMODE and INSNAME are added.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Point clouds: drawn from their scans, attached, cropped and stylized.
The fork's codec patch is resolved to the upstream pins: the point cloud
records landed in opencadcodec 5ef9376, carried through opencadkernel
68eeda1 and opencadgraph e204966.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bug:
The keep-recent-files footer on the Start page builds its [-] [count]
[+] buttons eagerly while constructing the widget, and the [+] step was
written as plain shown + STEP while the [-] button next to it already
used saturating_sub. shown comes from the input box, whose handler
keeps every ASCII digit with no length cap - so typing
18446744073709551615 (2^64-1) parses to usize::MAX and the addition
overflowed during view(), before the button was ever clicked. Debug
builds panic with "attempt to add with overflow"; release builds (no
overflow checks) wrap to a small number and request a nonsense limit.
The clamp in set_recent_limit runs only after the value is computed.
Reproduce:
1. Start page -> "keep recent files" box -> type
18446744073709551615.
2. Before: the next frame panics at widget construction (on render, no
click needed); release builds wrap the step silently.
3. After: no panic; pressing Enter or [+] applies the clamped limit and
the box resyncs to it.
Fix:
Mirror the [-] button: shown.saturating_add(STEP). At usize::MAX the
message carries usize::MAX, which the handler's existing
clamp-and-resync treats exactly like any other over-max entry, so both
step buttons are now saturating and the release-build wrap is closed as
well. on_submit has no arithmetic and needs no change. The regression
test calls start_page_content directly with the hostile string - it
fails at the same line instead of requiring a GUI session.
Bug:
Message::TabClose carried a vector index captured when the view message
was built. Closing several tabs in one batch (Close All / Close Others
with unsaved-changes dialogs, or a queue of continuation updates) let an
earlier close shift the vector before a later TabClose(idx) was handled:
self.tabs.remove(idx) either panicked (index past the end) or closed a
different tab than the one the user confirmed.
Reproduce:
1. Open several drawings and modify each so they all prompt on close.
2. Use Close All, or close two tabs in quick succession so both messages
are handled in one batch.
3. Before: panic in remove(idx), or the wrong tab closes while the tab
the user chose stays open (or its work is lost).
4. After: the chosen tab closes; an id already closed by an earlier
message is a no-op.
Fix:
TabClose now carries the tab's stable u64 id, resolved to a vector
position when the message is handled, not when it is built;
PendingClose::Tab stores ids the same way. All construction sites pass
tab.id (a raw usize index no longer type-checks), and
DocTabCloseAll/DocTabCloseOthers build their queues from live ids at
handling time. A missing id means the tab is already gone, so the
handler returns Task::none().
Picking the cloud opens the Extract Section Lines from Point Cloud
dialog with the reference's settings and defaults: entire cross section
or perimeter only, maximum points to process (slider and field, with
the estimated time), output layer (Use Current or a layer), colour,
lines or 2D polylines with their width, minimum line length and connect
lines tolerance (each measurable by two points on screen), collinear
angle tolerance (0-10) and Preview result. Create extracts; with the
preview it asks [Accept/Settings/Undo] and Settings reopens the dialog.
The settings are kept for the session. Automation action pc_section.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A dockable Point Cloud Manager lists each point cloud of the drawing (only
the selected ones while any is selected) with Regions (disabled, region
data is not read), Unassigned Points and Scans, the scans named by their
file stems. Each switch shows or hides points: the cloud, its unassigned
points, all scans or one scan. The hidden set is the cloud's
OCS_POINTCLOUD_VISIBILITY extended data (scan names plus *CLOUD_OFF /
*UNASSIGNED_OFF markers, app id registered), written as one undo step and
kept on save. The drawn points skip hidden scans by their index ranges,
and the hidden set is part of the placed-cloud key. Collapse all / expand
all, row highlight and a search box that filters rows (keeping parents of
matches). POINTCLOUDMANAGERCLOSE closes it; the pc_manager_toggle
automation action flips a switch.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
POINTCLOUDCOLORMAP asks for a cloud (or None for the drawing's default
schemes) and opens the Point Cloud Color Map dialog: intensity and
elevation tabs with the scheme list, New / Delete / Rename, number of
colours (2-25, resampled along the scheme), blend between the ends,
reverse, gradient or bands, the colorized range, the out-of-range
choice and, for elevation, the cloud's extents or a fixed range with its
band height. OK / Apply write the drawing's colour map (created under
ACAD_POINTCLOUD_COLORMAP_DICT when missing) and the cloud's colouring in
one undo step; Make stylization current sets the tab's stylization.
Values outside a scheme's range take the end colours, the scan colours
or are hidden. Automation action pc_colormap edits the dialog.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
POINTCLOUDATTACH opens the Attach Point Cloud dialog after the file is
chosen; its Attach button lives in the Attach Underlay list instead of a
separate Insert panel. A selected cloud brings the crop tools to the
right-edge toolbar. POINTCLOUDSTYLIZE sets the stylization with the
reference's prompts, the External References palette lists point clouds
(unload, reload, detach, path), and definitions keep the header extents.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Windows reports AltGr as Ctrl+Alt, so '@' and similar layout glyphs were
treated as shortcuts and dropped; polar input like @10<45 failed.
Fixes#1236
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The reference direction, base point and locked point went through f32,
so the drawn line drifted off true parallel.
Fixes#1387
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Insert > Reference: the PDF Attach button becomes an Attach Underlay menu
(PDF / DWF / DGN); its face runs the last one chosen.
- DWFATTACH, DGNATTACH and ATTACH on a .dwf/.dwfx/.dgn open the Attach
dialog for that kind: sheets or models with thumbnails (one chosen),
placement, path type, file details with the sheet / model size, and for
DGN the conversion units (sub units offer 1 / sub units per master as the
scale).
- DGN V8 true colours come from the ExtendedColors record packed in the
non-model attributes stream; the colour word's high part numbers them.
- A DGN model's extent includes each text's box (its length along the
baseline and 1.5 x its height), as the reference sizes a model.
- DWFx text uses the family named in its embedded (deobfuscated) font.
- DWF contrast pivots at 0.73 once colours are turned over for a dark
background.
- Hairline strokes are drawn solid one pixel wide, and underlay rasters are
made at or below their size on screen so those lines stay unbroken.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drops the Google Play banner and its image from the Start page sponsors; the OpenAEC sponsor stays.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- PDFOSNAP, DWFOSNAP and DGNOSNAP are separate; UOSNAP sets them all and
reads 2 while they differ. Enable Snap switches the selected kind's.
- DWFCLIP / DGNCLIP clip their own kind with the kind's prompts and message;
CLIP routes DWF and DGN underlays there; Enter at a corner asks again.
- The right-edge underlay tools show for DWF and DGN too (import is PDF
only).
- Underlay layers: DGN levels (V8 level table, "Default" listed as "0"; V7
used levels named from the level name table), hidden through the layer
override data with the DGN placeholder string first; a plotted DWF has
none.
- V8 colour read from its colour word (by level, index, or a true colour
drawn as its nearest index); 3D V8 elements drawn in plan (lines, line
strings, ellipses and arcs by their orientation, text); a model's extent
includes its text.
- DWF 6 TrueType text (font, height, rotation from the font opcode) and DWFx
glyph runs are drawn; the default W2D colour map is the measured one.
- Contrast pulls lightness towards a per-kind pivot as measured (PDF 0.5,
DWF 0.243, DGN 0.65).
- Zoom extents includes raster images and underlays whose frames are hidden.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A page shown small was drawn from its full-size raster and thin lines broke
up into dots. Once a zoom settles on another quarter-octave step, PDF, DWF
and DGN underlays are rasterised again near their size on screen (never
above the full-size raster), frames are requested until that happens, and
the adjusted-pixel memo is kept per raster size. V7 element weights no longer
widen strokes, matching V8 models.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The PDF Underlay and External Reference ribbon tabs are gone. While only
PDF underlays are selected their tools (Display in Monochrome, Create
Clipping Boundary, Remove Clipping, Show Underlay, Enable Snap, External
References, Edit Layers, Import As Objects) sit on the right-edge toolbar,
the switches drawn as on while on; while only xrefs are selected the xref
tools do. Contrast and fade stay in Properties. Toolbar tooltips are
translated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Attach PDF Underlay, Underlay Layers, PDF Import Settings and Import PDF
are laid out with rounded cards and accent titles, segmented controls for
path type, import layers and rotation, toggle chips for the on-screen
choices and import options, a page preview with previous/next for Import
PDF, always-visible file details, and a footer with help on the left and
the named action (Attach, Apply, Save, Import) on the right.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The node library leaves the overlay and becomes a dock panel (PanelId::
NodeGraph), docked on the right the first time the graph opens and movable
like any other panel; closing it closes the graph. It follows the block
palette's layout: title bar, then a search box with New / Open / Save
beside it, then the categories, of which only Objects starts open. Entries
are clicked (placed at the canvas top-left) or dragged onto the canvas.
The title bar (title, auto-collapse pin, close, drag to re-dock), the
toolbar icon button and the panel frame were copied across Properties,
Block Palette, External References and Browser; they are now
dock::title_bar, dock::tool_button and dock::frame, used by all of them.
Block Palette's two tool buttons gain tooltips, and External References'
Auto / Close tooltips are now translated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The codec and kernel repositories and crates are renamed opencadcodec and
opencadkernel. Inside OCS they are depended on under short keys, so code
reads `codec::`, `kernel::` and the new `graph::` (opencadgraph, the node
graph engine). File-format and protocol spellings stay as they were: the
ACIS product id `acadrust`, the ACADRUST_* switches and the plugin
version keys `acadrust_version` / `acadrust_source`.
A button left of MCP on the command line opens a translucent node graph
over the viewport, with a palette of object, input, math, logic, list,
text and geometry nodes added by click or drag. An object node owns
drawing entities and its rows are the Properties panel's own rows for
them: the single-object page is extracted from refresh_properties as
entity_property_sections, values use the control protocol's
property_json, and writes go through set_property_value with a property
target override, so the panel, MCP and the graph share one read/write
path. A list reaching an object row makes one entity per element. Each
graph action is one undo step; the canvas pans and zooms.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The ribbon definition beside each command stays the one source of its
label and icon. One cached lookup (modules::registry::ribbon_commands)
walks the core ribbon and the expanded Draw/Modify panels; the shortcut
list, the right-click menu, the grip menu and the command-line
suggestions read it.
- Context menu: command rows carry their ribbon icon; Undo/Redo and
Isolate use interface glyphs, Draw Order its ribbon icon; icons and
the caret fade on disabled rows.
- Grip menu: Stretch, Move, Rotate, Scale, Mirror and Copy icons.
- Suggestions: an icon column, aligned when a command has none.
- Shortcut list: dropdown entries were read as (label, command) though
the ribbon stores (command, label), so they never got a label or icon.
Reworked from #1449.
Co-Authored-By: MarcelP102 <30177694+MarcelP102@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>