Commit Graph
30 Commits
Author SHA1 Message Date
ramox81 fc047b3b38 Add multiline editing workflows 2026-08-22 20:20:35 +03:00
Hakan Seven 687023391e fix(flatten): project entities through kernel
Invalidate scene caches through entity updates and reject projections
that cannot be represented without changing geometry.

Refs #728
2026-08-17 21:59:09 +03:00
Ngo Quoc Viet 69604012d6 fix(flatten): project polylines and planar faces
Add initial FLATTEN coverage for polyline families, SOLID, and 3DFACE.

Refs #728
2026-08-17 21:40:17 +03:00
Hakan Seven 0be9c41773 fix(layers): protect locked entities
Keep locked-layer objects selectable for inspection while suppressing grips, property edits, command mutations, and stale editor writes.
2026-08-12 12:46:41 +03:00
Hakan Seven 67a767e23b fix(view): pause hover during navigation 2026-08-06 00:21:44 +03:00
Hakan Seven d1f9055901 feat(ui): refine ribbon and view navigation 2026-08-04 18:21:52 +03:00
Hakan Seven 3e6693b93f feat(locale): localize full interface 2026-08-02 22:09:25 +03:00
Hakan Seven 2c64888048 fix(blocks): preserve UCS transformations
Bake BEDIT frames into block-local geometry while keeping model and viewport UCS isolated. Normalize legacy nonzero block origins during load.
2026-07-30 19:50:33 +03:00
Hakan Seven c9aab122f0 feat(find): add find and replace
Closes #583
2026-07-30 17:56:54 +03:00
Hakan Seven d77eb8f419 fix(block): open nested editor tabs
Closes #538
2026-07-28 19:13:27 +03:00
Hakan Seven 05b044f367 perf(scene): make geometry edits incremental
Avoid full document, cache, and GPU rebuilds for entity deltas so add, delete, history, selection, and live polyline edits stay responsive on large drawings.
2026-07-28 17:16:27 +03:00
Hakan Seven d5be78a187 fix(selection): separate transient visibility
Keep object isolation out of persisted entity visibility and clear stale grips across block-editor transitions.

Refs #512

Refs #517
2026-07-27 23:36:02 +03:00
Hakan Seven 731df4a725 feat(cad): integrate standard codec coverage
Render, edit, query, select, and explode newly decoded standard entity variants. Pin acadifc de8d6b5 and preserve None color semantics.
2026-07-26 19:30:43 +03:00
Hakan SevenandClaude Fable 5 e7eb84b514 feat(pedit): convert prompt, join, fit/spline/decurve; join fixes (#263)
PEDIT reworked around a mode machine:

- Picking a line/arc asks "Object is not a polyline. Turn it into one?
  [Yes/No] <Y>" — Yes converts in place (arc keeps its bulge) and
  editing continues on the result. Pickfirst: an already-selected
  polyline skips the select step, a selected line/arc goes straight to
  the convert prompt.
- Join gathers with the normal selection system (single picks AND
  window/crossing boxes) and merges through the JOIN machinery.
- Fit replaces every segment with a classic equal-parameter BIARC: two
  arcs per segment meeting tangentially at an inserted knee, both
  segments at a vertex sharing that vertex's tangent — the whole run is
  tangent-continuous (verified: zero tangent jump on L/closed/zigzag/S
  shapes). Spline resamples the vertex frame as a uniform cubic
  B-spline (8 samples per span); Decurve straightens every bulge.
- Earlier hardening kept: undo snapshot before the mutation, immediate
  repaint, polyline-only pick validation.
- Vertex editing lives on grips, so no Edit-vertex submode; instead the
  vertex grip hover menu gains Break — a closed polyline opens at the
  vertex, an open one splits into two (interior vertices only),
  handled driver-side as an entity replacement.

JOIN itself: segs_of now emits one segment per span of an OPEN
polyline (bulges kept), so polylines merge with their neighbours —
PEDIT Join's set always contains the target polyline and used to abort
every time; plain JOIN had the same gap. JOIN also honours pickfirst:
launched with two or more objects selected it joins them immediately.

Closes #263

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 20:06:04 +03:00
Hakan SevenandClaude Fable 5 554921c66f fix(refedit): objects created during the session join the block
REFCLOSE only wrote the temp copies made at REFEDIT entry back into
the block, so anything drawn (or pasted / offset) during the session
stayed behind in model space (#423). The session now captures a
handle watermark at entry; on close, every current-space entity
allocated at or above it joins the working set — Save folds it into
the block through the same inverse transform, Discard removes it.
Covers every creation path with no per-command hooks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 11:13:47 +03:00
Hakan SevenandClaude Fable 5 f03288f120 fix(bedit): restore the view when leaving the block editor
Entering the block editor reframes the camera on the block's own
geometry, but nothing remembered where the model view was — Save /
Discard returned to the layout with the camera still parked at the
editor's framing (#425). The session now captures the camera on entry
and both exits restore it exactly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 11:06:42 +03:00
Hakan Seven 49c10bc806 feat(commands): step the remaining inquiry / solid commands (bucket E)
- ValuePromptCommand: CAL/QUICKCALC/QC (expression), FIND, FINDALL (search).
- SelectThenKeywordCommand (select the solid, then axis + value): SECTION,
  SLICE, 3DMIRROR, 3DROTATE. SLICE's optional TOP/BOTTOM stays typeable.
- TwoValuePromptCommand: PYRAMID (radius + height; sides typeable).

Left as-is by design: UNDO (bare already undoes one step — a correct default,
not a usage line); POLYSOLID (select a polyline then width + height — needs a
two-value-after-selection form) and 3DALIGN (six 3-D points) stay typeable.
2026-07-16 14:43:34 +03:00
Hakan Seven cf5362aeab feat(count): prompt COUNT for the tally mode
Bare COUNT now offers [All (by type) / By layer] as buttons instead of
immediately dumping the by-type tally. "All" dispatches COUNT TYPE, whose
output is identical to the old bare COUNT; "By layer" dispatches COUNT LAYER.
Counting a specific layer (COUNT <layer>) stays typeable. Finishes bucket B.
2026-07-16 13:57:44 +03:00
Hakan SevenandClaude Opus 4.8 3548de332c feat(block): BEDIT block editor as a dedicated space tab (#261)
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 <noreply@anthropic.com>
2026-07-14 13:03:04 +03:00
Hakan SevenandClaude Opus 4.8 2a72227d5d feat(attribute): route ATTMAN/BATTMAN to the attribute editor (ATTEDIT)
ATTMAN and BATTMAN previously produced a command-line listing of block
attributes. Route both to the attribute editor instead: extract the bare
ATTEDIT behavior into a shared open_attedit_dialog helper (edit the
selected block, or start the block-pick command) and call it from the
ATTEDIT, ATTMAN, and BATTMAN arms.

Kept as a match arm rather than an ocad.pgp alias so it works for
existing users, whose config pgp is only seeded on first run.

Replace the listing regression tests with one asserting ATTMAN and
BATTMAN behave byte-for-byte like ATTEDIT.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 09:37:54 +03:00
Hakan SevenandClaude Opus 4.8 91ba9f7699 feat(alias): centralize command aliases in user-editable ocad.pgp (#286/#288)
Command aliases (L→LINE, CC→COPYCLIP) were scattered across dispatch match
arms and CommandRegistration name arrays. Move them all into a single
user-editable file:

- assets/ocad.pgp: shipped default alias table (ALIAS,*COMMAND format),
  embedded and copied to config/ocad.pgp on first launch; only that user
  copy is read after. AA→AREA default closes #286.
- resolve_alias() rewrites the leading command token at the top of
  dispatch_command_inner, so aliases resolve for every path (families,
  plugins, Repeat menu). Args after the first space are untouched.
- Autocomplete hides alias keys and, when the whole input is an alias,
  surfaces its target command as the top (highlighted) suggestion so the
  highlight matches what Enter runs (AA→AREA, L→LINE).
- ALIASEDIT opens a new editor modal (add/edit/delete rows) with an Apply
  button; Apply persists to ocad.pgp, closing discards unapplied edits.
- Strip alias tokens from all 8 dispatch match-arm files and 71 module
  CommandRegistration arrays, keeping canonical/synonym/distinct-command
  names. ocad.pgp is now the sole source: deleting or remapping an alias
  there takes effect. CUI stays on the keyboard-shortcut panel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 12:39:22 +03:00
Hakan SevenandClaude Opus 4.8 e78e137664 fix(paper): keep model 3D solids off the paper-space sheet
The paper layout sheet pass reused the full model mesh set, so every
top-level 3D solid piled onto the paper origin — the sheet camera works
in paper coordinates, not model space. Guard `meshes` on
`inst.paper_sheet` the same way wires/hatches/images already are: the
sheet shows only paper-native content; the model's solids render inside
the floating content viewports (model camera + per-viewport scissor).

Also name 3DSOLID/REGION/BODY/SURFACE/MESH/SOLID/MULTILEADER in dxf_name
(they fell through to "ENTITY"), and add a SELHANDLES diagnostic that
reports the active space plus a per-type / per-block selection breakdown.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 23:29:18 +03:00
Hakan SevenandClaude Opus 4.8 5e4e7c1020 fix(commands): ADDSELECTED keeps CLAYER, adopts dimension style (#239)
Two follow-ups to ADDSELECTED:

- It no longer permanently changes the current layer/colour/linetype/
  lineweight. The template's properties are captured as the drawing
  defaults only while the launched draw command runs; a snapshot taken in
  cmd_add_selected is restored the moment that command ends (central hook
  in apply_cmd_result) or is interrupted by another command.
- Dimensions are supported: add_selected_verb maps each DimensionType to
  its DIM* command, and the template's dimension style is adopted as the
  current DIMSTYLE (restored afterwards). commit_entity_handle now stamps
  every new dimension with the current DIMSTYLE — the DIM commands left the
  default "Standard" on the entity, so a normal dimension also picks up
  the active style now.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 16:05:54 +03:00
Hakan SevenandClaude Opus 4.8 18fff5cf8c feat(command): ADDSELECTED draws a new object like the selected one (#239)
Take the first selected entity as a template, adopt its general
properties (layer, colour, linetype, lineweight, linetype scale) as the
current defaults, then start the matching draw command so the object
drawn next inherits them.

Supports Point, Line, Circle, Arc, Ellipse, all polylines (PLINE), Text,
MText, Spline, Hatch, Solid, Ray and XLine; other types report that
creation is unsupported. Registered for command-line autocomplete.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 18:42:26 +03:00
Hakan SevenandClaude Opus 4.8 56e1c03ac2 feat(layers): enforce layer lock (select/modify/fade + cursor badge)
Locked-layer objects were fully editable. Now they stay visible and
snappable but are otherwise protected:

- Not selectable: the five interactive pick paths (box, lasso, single
  click, cycling, box-release) plus SELECTALL and QSELECT skip locked
  entities.
- Not modifiable (defense-in-depth even if a handle slips through):
  transform_entities, erase_entities, apply_grip and the Properties
  commit all skip locked entities.
- Faded: entities on a locked layer render dimmed toward the background
  (render_style + wire tessellation); toggling lock re-tessellates.
- Snap still works: locked entities are intentionally kept in the wire
  set (visibility_ok untouched), so object snap keeps finding them.
- Feedback: a small padlock is drawn by the crosshair when hovering a
  locked object, and clicking one prints "Object is on locked layer …".

New Scene::is_layer_locked / locked_layer_name helpers centralise the
check (mirroring layer_hidden).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 13:10:39 +03:00
Hakan SevenandClaude Opus 4.8 86a59d6c7e feat(attedit): attribute editor dialog for blocks
Double-clicking a block reference that has attributes, or running ATTEDIT
on one, now opens an editor dialog listing every attribute (tag + editable
value) with OK / Cancel. OK writes the values back to the block, with undo
and a repaint; Cancel discards. A block with no attributes still enters
in-place block edit (REFEDIT) on double-click as before. (#192)

ATTEDIT opens the dialog directly when a suitable block is already
selected; otherwise it runs the pick command and the dialog opens once a
block is chosen. This replaces the earlier command-line, per-attribute
prompt flow, which is removed along with its __ATTEDIT__ sentinel path and
the now-unused attedit_set_attrs trait hook; the ATTEDIT command is reduced
to a plain block picker.

The dialog is a tab-scoped in-canvas modal (Plan B): its working copy holds
a document-local handle, so closing that tab or switching away dismisses the
editor rather than risk applying edits to another tab's document.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 08:05:25 +03:00
Hakan SevenandClaude Opus 4.8 e2a83a6487 feat(commands): add CLOSE, HIDE, VISUALSTYLES, QUICKCALC, HYPERLINK, XOPEN
Six more standard commands by reusing existing infrastructure:
- CLOSE: close the active tab (Message::TabClose)
- HIDE / VISUALSTYLES: per-viewport render mode (Message::SetRenderMode)
- QUICKCALC / QC: alias the CAL arithmetic evaluator
- HYPERLINK <url>: attach a hyperlink via the PE_URL XData record
- XOPEN: open a selected xref's source file (Message::OpenRecent)

COMMANDS.md updated to 214 done / 15 partial / 33 missing of 262.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 09:04:18 +03:00
Hakan SevenandClaude Opus 4.8 c19c18c2f2 feat(commands): expand standard CAD command coverage
Integrate a large batch of standard CAD commands and fix several
name/behaviour mismatches, with no product references in code.

3D solids (reusing the truck B-rep pipeline):
- SLICE, INTERFERE, PRESSPULL, POLYSOLID, PYRAMID, SECTION
- 3DROTATE, 3DMIRROR, 3DALIGN (cached-solid transforms)

Annotation / text:
- ARCTEXT, SPLINEFIT (Catmull-Rom to Bezier), DIMJOGGED, OBJECTSCALE
  (XData markers honoured by the existing geometry-gen / tessellator)

Blocks / misc:
- NCOPY (block-content extraction via explode_entity)
- OPTIONS, SYNCPVIEWPORTS, THICKEN, plus earlier toggles, aliases,
  system variables, and layer/style/view commands

POINTCLOUD/RECAP and UNDERLAYLAYERS/UOSNAP are intentionally left out:
they require a proprietary binary / PDF-layer parser, a GPU point
renderer, and real test files.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 08:23:58 +03:00
Hakan SevenandClaude Opus 4.8 0ca3954b5d feat(commands): integrate standard CAD commands and fix behavior gaps
Broad pass over the command set: integrate missing commands, wire
previously-unreachable ribbon/menu buttons, and correct name/behaviour
mismatches. Every UI command token now resolves (real handler where the
infrastructure exists, an honest "not yet implemented" status otherwise).

New commands:
- Draw: 3DPOLY, 2D solid (SO/SOLID2D), HELIX, TRACE, SKETCH, DIMCENTER
  (DCE/CENTERMARK)
- Modify/inquiry: REVERSE, MEASUREGEOM (MEA), DBLIST
- Data/manage: BASE, OVERKILL (exact-duplicate removal), AUDIT (read-only
  integrity report), SETVAR (system-variable get/set), SCRIPT (.scr runner),
  FINDNONPURGEABLE

Behaviour fixes:
- LINE and SPLINE gain Close/Undo; AREA computes area/perimeter in f64
  (correct at large coordinates)
- ATTEDIT/ATE unified so the alias and the ribbon button open the
  interactive editor; -ATTEDIT is the command-line form
- Linear/aligned/radius/diameter dimensions gain a text override (Text) and
  text angle (Angle) option
- INSERT gains Scale/Rotate options; COPY gains an Array option
- LINETYPE SET sets the current entity linetype; SETBYLAYER resets overrides
- UNDO accepts a step count

Integrations: standard dimension/block aliases (DLI/DRA/DAN, BMAKE,
EXPORTPDF, DDIM), drafting-aid and screen toggles (GRID/SNAP/POLAR/OSNAP/
DSETTINGS/CLEANSCREEN/QUICKPROPERTIES), viewport tiling
(CASCADE/HORIZONTAL/VERTICAL/VPJOIN), and customization entry points
(CUI/ALIASEDIT).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:27:35 +03:00
Hakan SevenandClaude Opus 4.8 bddc050b3e refactor: split four oversized files into submodule trees
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.

- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
  dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
  with thin delegating arms; the 66 fattest arm bodies move to topic
  methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
  mspace,project,selection,modify,group_layer,preview}. The impl Scene
  body is split across files via inherent-impl-per-file; struct, ctor,
  fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
  The 233-arm dispatch match becomes source-ordered per-family
  dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.

Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:51:29 +03:00