* Keep the active layout when saving DWG/DXF
The layout a file marks active (block *Paper_Space) was not kept on read, and on write *Paper_Space always went to the first tab, so every save made the first sheet active. Store it as Drawing::active_layout and write it as *Paper_Space again; tab order is unchanged.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Match the active layout by name without regard to case
paper_space_layouts and layout.rename now compare the active layout's
name case-insensitively, as Drawing::layout() does, so an active layout
stored as "s2" still resolves the "S2" tab.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Test case-insensitive active layout matching
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: ffishman <20211677+ffishman@users.noreply.github.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* security: write files atomically through an exclusive temp file (CWE-59, CWE-377)
Save, export, plot, autosave and the audit log each wrote their output by
putting bytes in a predictable sibling temporary path (`<path>.cadcraft-tmp`,
`<recovery>.tmp`, or the companion `.adt`) and renaming it over the real file.
Opening that pre-existing temporary path for a truncating write follows a
symlink planted there by another local user, letting them redirect the write
onto any file the victim can write before the rename.
Add a shared `atomic_write` helper that creates a fresh temporary file with
`create_new` (O_CREAT|O_EXCL) in the destination directory, writes through the
retained handle, flushes/syncs, and atomically renames it into place. An
existing entry (symlink or not) makes the exclusive create fail instead of
being followed. Route autosave, save, export, plot and the audit log through it.
The macOS CI cert importer likewise wrote the decoded PKCS#12 container to a
fixed name in a possibly shared temp directory; it now creates a private
per-run directory with `mktemp -d` and creates the file with noclobber.
Addresses findings rows 1, 25, 40 (CWE-59) and 19 (CWE-377).
* fix: preserve permissions during atomic replacement
* fix: restrict temporary permissions during exclusive creation
---------
Co-authored-by: skylartaylor <26588250+skylartaylor@users.noreply.github.com>
Double-clicking a viewport to enter MSPACE or sheet to enter PSPACE triggers a primary click on the first click that starts an idle selection window (pending_window). When the second click triggers dbl_primary, the handler executed an early return, leaving pending_window open and rendering an unwanted crossing/window rectangle across the screen. Reset pending_window and drag_window on double clicks and suppress primary click dispatch.
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Draw object transparency on screen, in exports and in plots
Transparency was read and saved (entity group 440, layer xdata, ByLayer and
ByBlock) but never drawn. Display lists now carry each object's effective
transparency (its own, its layer's, or the block reference's), and:
- the canvas (GPU and CPU paths), ui.render and PNG/SVG exports blend it;
TRANSPARENCYDISPLAY turns it off on screen and is now on by default, as in
AutoCAD (initial value 1);
- plots draw it only when "Plot transparency" is on: a page setup option
(PAGESETUP `plotTransparency`, a checkbox in the Page Setup Manager and the
Plot dialog), overridable per plot, with PLOTTRANSPARENCYOVERRIDE (0 never,
1 the setting, 2 always). PDF gets /ExtGState alpha, PNG plots blend, SVG
uses opacity. Plots without it are byte-identical to before.
The public DXF Reference has no plot layout flag for plot transparency, so
the option is kept in the session and in JSON, not in DXF/DWG.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Transparency fixes: attributes, PDF overlaps, drag previews
- Attributes draw with their own transparency (their definition's, layer 0
meaning the reference's layer, ByBlock the reference's) instead of the
block reference's.
- PDF plots stroke overlapping transparent objects one by one, so they build
up where they cross as in PNG plots; opaque output is unchanged.
- Drag and rubber-band previews follow TRANSPARENCYDISPLAY.
- Effective transparency is worked out only when it is drawn, reusing the
layer the property lookup already found.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Transparency: one PDF stroke per transparent primitive; opaque rebuilt previews
- PDF plots never batch two transparent primitives into one path. Block and
viewport contents share their reference's handle, so the per-object flush
missed them; each primitive now blends on its own, as in PNG plots and on
screen. Opaque output is unchanged.
- Previews the session rebuilds with the current properties (rubber bands,
copies of objects) are drawn opaque again: they carry CLAYER's
transparency, not the objects'. The GPU drag of the objects themselves
keeps following TRANSPARENCYDISPLAY.
- Tests for attributes on a transparent reference layer, attributes without a
definition, and the drag cache across the TRANSPARENCYDISPLAY toggle.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Selection like AutoCAD: colour highlight and the Options Selection tab
Selecting or hovering an object outlined each filled primitive (TrueType
glyphs, dimension and leader arrowheads, solid hatches, wide polylines)
by the rectangle around its triangles, and dashed everything else. A
selected dimension's text became a row of dashed boxes, one per glyph,
and its closed arrowheads small rectangles.
Selected objects are now redrawn in the selection colour: lines solid,
fills filled half see-through (so the lines and text on a highlighted
hatch stay visible), and the whole object reads as selected, text and
arrowheads included. A wipeout is always outlined, since filling it would
hide the drawing under it.
The Options dialog's Selection tab is laid out as AutoCAD's, with the
settings CADCraft can act on, each one AutoCAD's variable, kept in the
user profile:
- Selection modes: noun/verb selection (PICKFIRST), Shift to add
(PICKADD), Object grouping (PICKSTYLE bit 1, now saved in the profile).
- Selection effect color (selectionColor, an interface preference; null
is the theme's).
- Grips: Show grips (GRIPS) and the object selection limit for display of
grips (GRIPOBJLIMIT, 100; 0 no limit): grips are neither drawn nor
picked beyond it.
- Selection preview (SELECTIONPREVIEW): the object under the cursor is
highlighted when a command is active (2) and when none is (1).
- Visual Effect Settings: the selection area effect (SELECTIONAREA,
WINDOWAREACOLOR 150, CROSSINGAREACOLOR 100, SELECTIONAREAOPACITY 25)
and the Selection Preview Filter (PREVIEWFILTER 3: 1 objects on locked
layers, 2 xrefs, 4 tables, 8 multiline text, 16 hatches, 32 groups).
As in AutoCAD these are typed, not on the dialog: HIGHLIGHT (0 shows only
the grips of selected objects; not saved, so every session starts
highlighted), SELECTIONEFFECT (1 the selection colour, 0 dashed lines with
fills outlined along their real boundary) and PREVIEWEFFECT (the preview
dashed 0, thicker 1 or both 2).
Left for later, as CADCraft lacks what they control: lasso, grip tips and
menus, group grips, grips within blocks, associative hatch selection,
command and property preview, PICKDRAG, PICKAUTO and PROPOBJLIMIT.
DisplayList::fill_outlines returns the boundary of the region a filled
primitive covers as closed polylines (edges only one triangle has; the
slab filler's horizontal cuts, which need not line up between trapezoids,
are split at every x on their line and kept where an odd number cover
them), falling back to the bounding box over 600,000 vertices. The GPU
and CPU highlight paths and the drawing comparison overlay share the same
looks.
The new labels have Ukrainian rows (the required catalog); other
languages fall back to English.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: EP995LAB <293597958+EP995LAB@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Cody Vogt <18035288+codyvogt@users.noreply.github.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* doc: Space::is_paper/layout/tab_name helpers replace hand-written matches
Twenty-seven call sites in 15 files across engine, io and ui-egui matched Space by hand to get
"is this a layout", "which layout" or "Model or the layout's name". Route them
through three small helpers on Space instead. No behaviour change.
This also makes adding a space kind a few-file change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* doc: keep Space::Model comparisons that no helper shortens; test the helpers
Only the sites that repeated the same match (tab name, layout name,
paper lineweights) go through the helpers; plain Model comparisons and
plot_window's match on (space, plotArea) stay as they were.
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>
Layers and objects get a PlotStyle property (ByLayer/ByBlock/name) applied
through named tables (built-in default.stb and monochrome.stb, our own
definitions). DXF keeps the names in the ACAD_PLOTSTYLENAME dictionary of
ACDBPLACEHOLDER objects with group 390 on layers and objects; tables kept in
the drawing travel in a CADCRAFT_PLOTSTYLES XRECORD. PLOTSTYLE sets an object's
or the current (CPLOTSTYLE) style; STYLESMANAGER lists, creates, edits, deletes,
loads and saves tables in our own JSON format (docs/plot-styles.md). A Plot
Style Manager dialog edits a table's styles and the layout's table; the
Properties palette shows the current plot style and table.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A PlotStyleTable model in doc with our own built-in tables (default.ctb keeps
object properties, monochrome.ctb prints black, grayscale.ctb prints the grey of
each colour's luminance). The render builder resolves each object's style by its
index colour (true colours by the nearest index) and applies colour, screening,
linetype and lineweight. PLOT/EXPORTPDF use the page setup's table (or the
plotStyleTable option); layouts with Display plot styles (PAGESETUP
displayPlotStyles, DXF plot flag 2) show it on screen and in PNG/SVG exports.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Typed VPLAYER ran its JSON form with no parameters and ended, so its
options ran as commands (F started FILLET). It now loops on
?/Color/Freeze/Thaw/Reset/Newfrz/Vpvisdflt until Enter, asks for layer
names (wildcards, comma lists) and then which viewports to change:
All/Select/Current/Except current (Current by default inside a viewport,
Select by point on the sheet in paper space). Changes go through
viewport.set, layer.new and layer.set; the session is one undo step.
The Model tab refuses it.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Typed LAYOUT ran its JSON default and ended, so the option and the
layout names typed after it ran as commands. It now asks for an option
(Copy/Delete/New/Template/Rename/SAveas/Set/?, Enter = Set) and the
layout name(s) the option needs, with the current layout as the default.
The options run the layout.* command bodies, so a refused name re-prompts
and the command is one undo step. Template and SAveas report that they
are not available yet and end.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Menu items open their missing dialogs; COUNT shows its result; New Layout asks for a name (#126)
Eight menu items ran their JSON form with no parameters and changed nothing.
Typed or chosen from a menu they now do what the menu promises; JSON calls
still run the command and never open a dialog.
- New crates/ui-egui/src/managers.rs: Linetype Manager (load from the
library, set current, global scale, pattern preview), Point Style
(PDMODE tiles drawn in code, size relative/absolute), Table Style and
Multileader Style (list, set current, new, edit properties), Page Setup
Manager (per layout: paper, orientation, plot area, fit/scale, center,
lineweights) and Constraint Settings (infer, bars, transparency, dynamic
constraints, AutoConstrain types and tolerances). All changes go through
their commands (app.run), so they are undoable and scriptable.
- menus::run_ui_command routes LINETYPE/LT, DDPTYPE, TABLESTYLE/TS,
MLEADERSTYLE/MLS, PAGESETUP and CONSTRAINTSETTINGS/CSETTINGS without
parameters to the dialogs; dialogs::show dispatches them.
- COUNT returns a `message` (per-block counts and total) that the command
line shows; Session::start echoes multi-line messages line by line.
- LAYOUT.NEW from the menu or command line prompts
"Enter name of new layout <LayoutN>:"; Enter takes the default, a taken
or invalid name is reported and asked again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Move COUNT test away from other PRs' hunks to avoid merge conflicts
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- Layer Properties Manager: filter tree (All / All Used Layers) with search, sortable table
(Status, Name, On, Freeze, Lock, Plot, Color, Linetype, Lineweight, Transparency,
New VP Freeze, Description; VP Freeze / VP Color inside an MSPACE viewport), inline
rename and description, ACI + true-colour picker, linetype picker with Load from the
library, lineweight picker, layer states save/restore/delete.
- Engine: qselect rewritten ({type, property, operator =,!=,>,<,*, value, mode new|append|
exclude, applyTo}) + qselect.info; layerstate.list/delete/rename; layer list reports
used layers and states; Layer.vp_freeze_new (DXF flag 2, applied by MVIEW) and
layer.set newVpFreeze; per-viewport layer colours (Viewport.layer_colors, vplayer
colors, honoured by the renderer); vplayer defaults to the active viewport; QPMODE
setting/sysvar/toggle; properties.set length/angle for lines.
- Canvas: constraint bars with code-drawn glyphs and coincident markers, dynamic
dimensional constraints (aligned/horizontal/vertical/radius/diameter/angular) with
name=value labels and lock icon, honouring CONSTRAINTBAR/DCDISPLAY; cached per
drawing revision; double-click a label to edit its expression (parameters).
- Quick Properties palette near the selection (status-bar toggle), Quick Select dialog,
Parameters Manager (edit, add user parameter, delete).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Double-click a viewport (or MS) to edit model space inside it; the screen view maps
consistently so picks, snaps, grips and previews work in model units, and zoom/pan
change the viewport's view (or the sheet when the viewport is locked). PS or a
double-click outside returns to paper space.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>