Commit Graph
120 Commits
Author SHA1 Message Date
Hakan SevenandClaude Opus 4.8 9b112ce12c feat(scene): PERF frame-budget HUD for wire re-tessellation cost
Phase 5.3 (CPU tessellation slice). Add a `PERF` command that toggles an
overlay on the active viewport showing the cost of the most recent wire
re-tessellation: ms, wire count, geometry epoch. Anchored top-left via
position_canvas_overlay.

Timing is captured at the wire-cache miss paths (model_tile_wires_arc,
paper_sheet_wires_arc) and stored in Cells on Scene, read directly by the
UI view (Scene is single-threaded / Rc-based, so build_primitive and view
share a thread). Reads ~0 ms on a warm cache, so it isolates the exact
work a miss costs — the slice 2.2 / 3.1 / 3.3 each move, making them
PR-to-PR comparable.

GPU upload/draw/GPU-wait spans (need wgpu timestamp queries) remain open.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-05 01:07:17 +03:00
Hakan SevenandClaude Opus 4.8 70702d063f perf(hash): swap std HashMap/HashSet for rustc-hash FxHash
Phase 4.1. Handle / u64 keys dominate the hot maps (block_defn,
hatch / image / mesh caches, draw-depth map, viewport wire caches);
the default SipHash is wasted work on integer keys. Alias the std
types to rustc_hash::FxHashMap / FxHashSet crate-wide so every map and
set — including the cross-module draw-depth map shared between scene
and the GPU pipelines — uses the faster hasher consistently.

Mechanical: no behavioural change. Constructors moved from ::new() to
::default() (Fx variants carry no RandomState). Build + 13 tests green.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-05 00:35:53 +03:00
Hakan SevenandClaude Opus 4.8 3098523b8d perf(io,scene): drop redundant purge walk, fuse world-offset scan
Phase 1.1: resolve_xrefs now purges corrupt entities inline as it
merges each xref and returns the dropped count, removing the second
full-document purge_corrupt_entities walk in the FileOpened handler.
Every xref-bearing open saves one O(N) entities() pass.

Phase 2.4: split compute_world_offset into offset_prep / offset_centroid
/ world_offset_from_centers; centroid accumulation now rides the existing
cache-handle walk in build_derived_caches. Two O(N) entity walks collapse
into one, with identical MSPACE-membership filtering preserved.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-05 00:32:39 +03:00
Hakan SevenandClaude Opus 4.8 e0e7897952 feat(statusbar): isolate / hide objects with status pill
Add a hidden-entity set to the scene that the tessellation visibility
test skips, so hidden objects neither render nor hit-test. New commands
ISOLATEOBJECTS (show only the selection), HIDEOBJECTS (hide the
selection) and UNISOLATEOBJECTS (restore). An ISO status pill lights up
while anything is hidden and restores everything on click.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-04 22:51:23 +03:00
Hakan SevenandClaude Opus 4.8 a584e772ba fix(textstyle): open Text Style manager from the ribbon Manage button
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 <[email protected]>
2026-06-03 20:52:11 +03:00
Hakan SevenandClaude Opus 4.8 e0c5db9e0c feat(mleaderstyle): add Multileader Style editor window
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 <[email protected]>
2026-06-03 20:25:14 +03:00
Hakan SevenandClaude Opus 4.8 7bf9ce31ae feat(model): 3D solid modelling tab — primitives + boolean ops
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 <[email protected]>
2026-05-31 19:27:06 +03:00
Hakan SevenandClaude Opus 4.8 4acb820e01 fix(ribbon): dismiss stuck style dropdown on viewport click
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 <[email protected]>
2026-05-31 14:57:50 +03:00
Hakan SevenandClaude Opus 4.8 2627d06224 feat(text): in-place editors for all text entities
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 <[email protected]>
2026-05-31 14:44:18 +03:00
Hakan SevenandClaude Opus 4.8 09e7e90aae feat(draworder): cross-type draw order + context menu
DRAWORDER now affects rendering immediately (bump geometry epoch so the
sort cache rebuilds) and front/back anchor to the block's full effective
sort range instead of only existing table entries, so bring-to-front
actually lands on top. The render fallback sorts table-absent entities by
their own handle.

Draw order now applies across entity types, not just within a type. A
per-entity draw-order rank (SortEntitiesTable override or own handle,
ranked per block) is encoded as a small signed clip-z bias in the wire,
hatch, image, and 3DFACE pipelines. The shared LessEqual depth buffer then
orders fills, lines, rasters and 2D solids against each other regardless of
pass order — without touching model coordinates. 3D meshes keep real
geometric depth; wipeouts stay always-on-top.

Adds a Draw Order submenu to the viewport context menu (Bring to Front,
Send to Back, Bring Above/Send Under Object). The above/under items run an
interactive reference-object pick, then reorder the captured selection.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-05-30 21:29:01 +03:00
Hakan SevenandClaude Opus 4.7 92f368f275 fix(layer): refresh viewport after LAYOFF/LAYFRZ/LAYON/LAYTHW/LAYLCK… (#42)
The eight layer-state commands (LAYOFF, LAYFRZ, LAYLCK, LAYULK, LAYON,
LAYTHW, LAYISO, LAYUNISO) mutated `document.layers` directly through
`dl.turn_off()` / `dl.freeze()` / `dl.lock()` / … and then called
`refresh_layer_panel()` — but never bumped the scene's geometry epoch.
The 3D viewport caches its uploaded geometry keyed by that epoch, so
visibility / freeze changes only took effect once something else
triggered a re-render. Pressing Esc was the workaround because the Esc
handler calls `deselect_all()`, which internally bumps geometry.

The Layer Properties panel toggles already did this (their handlers in
`update.rs` call `scene.bump_geometry()` after each freeze / visibility
toggle), which is why the panel worked and only the command path
exhibited the lag.

Add `scene.bump_geometry()` after the layer mutation loop in each of
the eight command branches so the viewport repaints immediately. Lock /
unlock don't strictly affect rendering today but are bumped for
consistency — selection / grip code may grow lock-aware later.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-29 23:17:58 +03:00
Hakan SevenandClaude Opus 4.7 9db206f310 feat(select): Select Similar + Quick Select panel (#28)
Two ways to extend the current selection by entity type + layer:

* `Select Similar` (right-click → Select Similar, or `SELECTSIMILAR` /
  `SELSIM`): for every (type, layer) pair in the current selection, add
  every entity in the active layout that matches the pair. The seed
  selection stays selected; matches already selected are not
  double-counted.
* `Quick Select` (right-click → Quick Select…, or `QSELECT` / `QS`):
  opens a centred floating panel with Object-type and Layer pick_lists
  (populated only with values that actually exist in the active layout)
  and an "Append to current selection" checkbox. `(Any)` in either slot
  skips that filter. Apply replaces the selection (or extends it with
  Append on) and reports the match count on the command line. Cancel,
  Esc, and outside-click all dismiss without applying. When opened with
  a selection present, the panel pre-fills both filters from the first
  selected entity so QSelect doubles as an editable Select Similar.

Scoped to entities owned by the active layout's block-record so a paper
layout's QSELECT never reaches into model-space entities (and vice
versa). Entity-type names live in a single `entity_type_name` helper in
`entities::traits` to keep the UI strings and the filter keys aligned.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-29 20:30:56 +03:00
Hakan Seven 89fcb21b46 fix(layer): propagate LAY* command changes to panel + dropdown (#39)
LAYOFF / LAYFRZ / LAYLCK / LAYON / LAYTHW / LAYULK / LAYISO /
LAYUNISO mutated the document's layer table (\`turn_off\` /
\`freeze\` / \`lock\` / …) and then called \`sync_ribbon_layers\`,
which feeds the ribbon dropdown from \`self.tabs[i].layers.layers\`
— the \`LayerPanel\` cache. That cache was never refreshed from
the document for these commands, so the dropdown stayed wrong and
the Layers Properties Manager kept showing the old visibility /
lock / freeze icons.

Add \`OpenCADStudio::refresh_layer_panel\` that runs
\`LayerPanel::sync_with_viewports\` from the live document before
calling \`sync_ribbon_layers\`. Replace every direct
\`sync_ribbon_layers\` in \`commands.rs\` (all of them sit inside
LAY* arms) with the new helper.

Closes #39
2026-05-29 01:30:02 +03:00
Hakan Seven 8f02e1ca07 fix(dyn-input): re-sync fields immediately after point commits (#35)
`sync_dyn_fields` only ran during `ViewportMove`, so a typed-coord
or click-driven point commit left the previous iteration's field
shape in place until the user nudged the mouse. After the first
LINE click that meant the stale `[X, Y]` (built when there was no
base) kept serving the next point's input as cartesian even though
the command-default for a "Point with base" is now polar
`[Distance, Angle]`. The original #35 fix preserved a
`,`-reshaped cartesian set on purpose, but the same machinery now
also held onto a never-explicitly-chosen `[X, Y]` carried over from
"no base" → "has base".

Track that intent explicitly with `dyn_user_reshaped` (set in
`dyn_comma_advance`, cleared on point commit and command start)
and only treat a non-matching shape as acceptable while that flag
is on. Re-run `sync_dyn_fields` from every point-commit path
(command-line typed coord, mouse click, dynamic-input locked
commit) so the freshly updated `has_base` state immediately picks
the right default and the user sees polar fields without having
to move the mouse first.
2026-05-29 00:57:37 +03:00
Hakan SevenandClaude Opus 4.7 e27ab79b08 fix(menu): wire EXIT / QUIT commands to the close path (#41)
The OCS main menu's "Exit Open CAD Studio" button dispatched
`Message::Command("EXIT")` but `dispatch_command` had no arm for it,
so the click was swallowed. Route `EXIT` and `QUIT` through
`Message::WindowCloseRequested` so the unsaved-changes dialog runs
first and the app then exits via the same path as the OS-window close.

Closes #41

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-28 22:55:08 +03:00
Hakan Seven 8a510c563c fix(render): adapt mesh + hatch load colours to background
`adapt_to_bg` (pure black → white on dark bg, pure white → black on
light bg) was only running through `render_style`, which the wire and
per-frame hatch paths already use. The mesh population paths and the
file-load hatch path went straight through `aci_to_rgba`, so:

- ACIS solids / regions / bodies appeared in their raw ACI colour
  even when that colour was pure white on a white paper bg.
- The initial hatch upload used the unadapted colour for the first
  frame after load (`synced_hatch_models` then re-ran adaptation per
  frame, so the issue cleared after one redraw — but visible).

Now every mesh / hatch creation site funnels through
`render_style_for` + `adapt_to_bg`:

- `build_derived_caches` (load): uses the default model bg as the
  adaptation target.
- `populate_meshes_from_document`: uses `self.render_style` so the
  per-frame paper / model bg selection applies.
- New `Scene::recolor_meshes` rewrites every cached mesh's colour
  field through `render_style`; called from `BACKGROUND` (after the
  user changes bg) and `set_current_layout` (Model ↔ paper bg
  switch) so ACIS mesh colour tracks the live bg without re-
  tessellating ACIS geometry.

Wipeout fills stay bg-coloured by design (that's their job). Raster
images skip adaptation — pixel data is not entity colour.
2026-05-28 21:15:28 +03:00
Hakan Seven e3c962bdd1 fix(viewport): adapt entity colours to visible bg
`model_wires_for_viewport` was tessellating with `self.bg_color` (the
model bg), so model content rendered inside a paper-layout viewport
adapted to a dark bg even though the transparent shader now reveals
the PaperCanvas sheet behind it — white wires stayed white on a light
sheet. Pass the paper bg in a paper layout.

Wire cache also needed an explicit invalidation when the bg or the
active layout changes; otherwise the cached, already-adapted wires
were returned against the new bg unchanged.

- BACKGROUND command bumps `geometry_epoch` after both branches
- new `Scene::set_current_layout` setter bumps on actual change; layout
  switch + history restore use it
2026-05-28 18:28:18 +03:00
Hakan SevenandClaude Opus 4.7 6fe25e4b5f feat(viewport): interactive VPORTS model tiled presets
Model space'de VPORTS artık iki aşamalı: bare VPORTS bir yapılandırma
istiyor (SIngle/2H/2V/4), sonraki komut-satırı girdisi düzeni kuruyor
(boş giriş = SINGLE). set_model_tile_layout normalized rect listesiyle
tiled düzeni değiştiriyor:
- SINGLE: tek tam-ekran
- 2H: üst/alt
- 2V: sol/sağ
- 4: 2x2

awaiting_vports app flag'i prompt sonrası girdiyi yakalıyor. Paper-space
VPORTS davranışı değişmedi.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-27 22:52:55 +03:00
Hakan SevenandClaude Opus 4.7 fda0f2dbb9 refactor(ui): remove the viewport navigation bar
Sağ kenardaki dikey orbit/pan/zoom/zoom-extents araç çubuğu tümüyle
kaldırıldı: viewport render'ı, overlay::nav_toolbar fonksiyonu,
show_navbar state + ToggleNavbar mesajı/handler'ı, NAVBAR komutu, View
şeridindeki "Navigation Bar" aracı ve navbar modülü/ikonu. Aynı
gezinme işlemleri komutlar (3DORBIT, PAN, ZOOM*) ve ViewCube üzerinden
erişilebilir durumda.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-27 17:49:23 +03:00
Hakan SevenandClaude Opus 4.7 874226bd43 feat(input): relative coordinate entry (@/#) and DYN default — #26
Koordinat girişi artık göreli/mutlak ayrımını destekliyor:
- `@x,y[,z]` → son girilen noktaya göreli (UCS eksenlerinde döndürülür)
- `#x,y[,z]` → her zaman mutlak (DYN durumundan bağımsız)
- ön ek yok → DYN açıksa göreli, kapalıysa mutlak
İlk noktada referans olmadığından göreli giriş mutlağa düşer. Çözülen
WCS noktası last_point olarak saklanıyor, böylece ardışık göreli
girişler zincirleniyor.

parse_coord artık (Vec3, CoordKind) döndürüyor; relative offset için
ucs_rotate_vec eklendi (origin translation olmadan UCS rotasyonu).
UCS ORIGIN komutu prefix'i yok sayıp mutlak kalıyor.

Ayrıca ViewCube snap refactor'undan kalan kullanılmayan kod temizlendi:
angle_close, active_viewport_yaw_pitch, CubeRegion::snap_angles.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-27 11:40:28 +03:00
Hakan SevenandClaude Opus 4.7 5da32ff202 refactor(entities): collocate ui_name + dxf_name into entities/names.rs
Two near-identical match-on-EntityType tables lived far apart:
scene/properties.rs::entity_type_name returned mixed-case UI labels;
app/commands.rs::entity_type_name returned uppercase DXF record names.
Both enumerated ~30 variants; adding a new entity meant remembering to
touch two files in two crates' worth of source layout.

Move both into a single entities/names.rs as `ui_name()` and
`dxf_name()`. Adjacent so a new variant gets both labels added at once;
function names make the intended audience explicit at the callsite.

scene/properties.rs and app/commands.rs each lose their local match
plus one re-export, gaining a `crate::entities::names::*` call.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-26 17:18:47 +03:00
Hakan SevenandClaude Opus 4.7 e78321190a refactor(commands): per-entity MassProps + TextContent traits
Two free helpers in app/commands.rs lived as big match-on-EntityType
blocks: massprop_entity (Circle/Arc/Line/LwPolyline/Ellipse area +
perimeter + centroid, ~140 lines) and entity_text_content /
replace_entity_text (Text/MText/AttributeDefinition/AttributeEntity).

Move each to its own trait in entities/traits.rs and implement
per-entity:

  MassPropsCalc  — Circle, Arc, Line, LwPolyline, Ellipse
  TextContent    — Text, MText, AttributeDefinition, AttributeEntity

EntityTypeOps gets dispatch shims that route to the trait via the
existing macro, so callsites just call entity.mass_props() /
entity.text_content() / entity.replace_text(search, rep).

The remaining free helpers in commands.rs (entity_list_details,
entity_extra_info, entity_type_name, build_data_extraction_csv) are
single-command formatting helpers tightly coupled to LIST / EXTRACT /
text-format output. Distributing them as per-entity methods would
inflate every entity file with command-side formatting concerns
without making the command-side any cleaner — left in place.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-23 23:30:34 +03:00
Hakan SevenandClaude Opus 4.7 ecdb0cd0a0 chore(release): bump to 0.4.0
Fix repo URLs to canonical HakanSeven12/OpenCADStudio casing.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-23 17:32:29 +03:00
Hakan SevenandClaude Opus 4.7 ef1f9a08d6 chore: rename H7CAD to Open CAD Studio
Joining the OpenAEC Foundation (open-aec.com). Crate/struct become
OpenCADStudio, user-facing strings use the spaced "Open CAD Studio"
form, repo URLs point to HakanSeven12/open-cad-studio. Logo (window
icon + assets/logo.svg) redrawn with OCS initials. Drop examples/
binaries — unused.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-23 17:16:15 +03:00
HakanandClaude Opus 4.7 e9488f99dd perf(wire): move LWDISPLAY toggle from CPU rebake to wire shader uniform
LWDISPLAY (Show Lineweight) flipping the toggle no longer triggers a full
retessellate. `render_style_for` always bakes the entity's resolved (layer-
inherited) lineweight, and the wire shader reads `Uniforms.lwdisplay_enable`
to either honour the per-vertex half_width or collapse the quad to a 1 px line.

Side effect: PDF export now uses the real lineweight regardless of LWDISPLAY,
matching AutoCAD's plot semantics (LWDISPLAY only affects screen render).

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-23 09:45:24 +03:00
Hakan SevenandClaude Opus 4.7 fb3dd58d09 fix(polyline): correct wide-polyline fill band arc center + add LWDISPLAY toggle
Wide LWPolyline/Polyline2D fill bands now sit on the centerline:
- polyline_segment_fill arc center matched explode.rs / acadrust convention
  (signed d_perp = r·(1-b²)/(1+b²), handles major arcs correctly)
- per-vertex hw0/hw1 taper applied along arc; tess density 24/circle
- synced_hatch_models subtracts hatch_offset from band boundary so it lives
  in the same offset-rel space as the wire tessellation

LWDISPLAY:
- new command `LWDISPLAY [ON|OFF]` toggles header.lineweight_display
- LWT status-bar pill (between ORTHO and POLAR) drives the same flag
- bump_geometry() on change so the viewport re-tess immediately

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-23 07:15:26 +03:00
Hakan SevenandClaude Opus 4.7 4cca6363ef feat(app): surface round-trip HeaderVariables via DWGPROPS + USERI/USERR
The "round-trip metadata" fields (timestamps, GUIDs, file identity,
user-script scalars) were parsed and re-emitted on save but never
exposed anywhere, so users couldn't confirm what the file actually
carried. Add two command-line commands that read / edit them:

- DWGPROPS / DWGPROP dumps the header to the command-line output:
  create / update / total-edit / user-elapsed timestamps,
  fingerprint_guid, version_guid, code_page, menu_name, hyperlink_base,
  project_name, stylesheet, required_versions, measurement (with a
  human label), proxy_graphics, tree_depth, plus the five USERI / USERR
  slots and the user_timer flag.
- USERI <1-5> <int> / USERR <1-5> <real> writes one of the five
  document-scoped scalar slots and marks the tab dirty so the value
  rides the next save. Lets users park drawing-scoped numbers in the
  same place AutoCAD scripts have always used them, even though we
  don't ship a LISP / DIESEL runtime.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-20 05:48:07 +03:00
Hakan SevenandClaude Opus 4.7 4adbb20c5d feat(scene): honour the last DimStyle fields end-to-end
Tessellation and DIMBASELINE pick up the few DimStyle fields that were
still hard-coded or ignored:

- DIMTMOVE = 1 draws a connector segment from the dim-line anchor to the
  saved text_middle_point when the text has been moved
- Leader arrows are resolved via the leader's DIMSTYLE → DIMLDRBLK; the
  shape (closed-filled / open / dot / tick / …) is drawn through the same
  arrow emitter the dim path uses, including fill_tris for filled blocks
- DIMBASELINE picks up DIMDLI from the active DimStyle instead of the
  hard-coded 1.5 increment
- DIMTOFL / DIMTIX / DIMATFIT / DIMUPT / DIMTXTDIRECTION are read so the
  fields round-trip on save; their effect is at dim creation, not render,
  so they're acknowledged with a no-op block

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-19 13:37:37 +03:00
Hakan Seven 66243e53ca feat: correct viewport scale calculation with correct dimension and text scaling 2026-05-19 00:26:08 +03:00
Hakan SevenandClaude Opus 4.7 412fb857ba chore: drop legacy comments and the last unused dead_code allows
* io/xref.rs — replaced the 7-line "BlockRecord::is_loaded turned out to
  be unreliable" rationale with a one-liner. The reverted experiment
  lives in git history (e88a946, 0996b75).
* refedit::RefEditSession.insert_handle — set at construction but never
  read; the "kept for future REFCLOSE DISCARD" TODO can come back via
  git history when that feature lands.
* scene::mod — dropped the placeholder MeshModel re-export; nothing
  outside `mesh_model` consumes the bare name and MeshLodSet is the
  pipeline-facing type now.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-16 02:04:41 +03:00
HakanandClaude Opus 4.7 e88a946176 feat(xref): honor BlockRecord is_loaded — skip Unloaded xrefs
When the host DWG marks an xref as Unloaded (via XREF→Unload in
AutoCAD), the user explicitly chose NOT to load that reference. We
were ignoring that and pulling the external file in anyway, which
on large drawings could push GPU memory past the device budget.

Bump the acadrust dep to the branch that exposes
`BlockRecord::is_loaded`, then short-circuit `resolve_xrefs` for
any entry with `is_loaded == Some(false)`. New `XrefStatus::Unloaded`
surfaces this in the command-line log so the user can see which
references were skipped (and can re-load them via the XREF dialog).

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-14 11:20:11 +03:00
HakanandClaude Opus 4.7 586df77b2c feat(io): show loading overlay while opening CAD files
Big DWG/DXF files block the UI for seconds during parse + cache build,
leaving the user wondering whether the app froze. Split the file-open
flow into pick → load and show a modal overlay during the load: file
name, size, phase label (Reading / Parsing / Building caches /
Finalizing), animated indeterminate bar, and Cancel button.

Phase is tracked via a shared AtomicU8 written by the loader thread
and read by the overlay each frame. Cancel hides the overlay and
discards the result; the parser thread runs to completion in the
background since acadrust has no interrupt hook.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-13 09:59:07 +03:00
Hakan ca07268c7c cargo fmt 2026-05-12 10:36:15 +03:00
Hakan Seven d7422b9396 fix: store arc angles in radians 2026-05-03 20:14:28 +03:00
Hakan Seven 1b4c5e13e5 fix: keep open drawing when creating new file 2026-05-03 19:55:38 +03:00
Hakan SevenandClaude Sonnet 4.6 5f3182fa9a fix: NAVVCUBE and UCSICON commands now properly toggle visibility
NAVVCUBE: propagate show_viewcube flag through ViewportPane and the wgpu
Primitive so the ViewCube pipeline skips upload/render when hidden.
UCSICON: bare command (no subcommand) now toggles current state instead
of printing usage info.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-04-24 01:31:52 +03:00
Hakan SevenandClaude Sonnet 4.6 1ec53a4730 feat: view tab widget toggle commands and unified SVG icon color scheme
Integrate NAVVCUBE, NAVBAR, PROPERTIES, FILETAB, LAYOUTTAB, TOOLPALETTES
and SHEETSET commands to toggle UI widgets at runtime. Add 15 new SVG icons
for view module tools previously using glyph fallbacks. Restyle all SVG
icons to use the established two-color scheme: #e0e0e0 for passive geometry,
#4cc9f0 for active/accent elements.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-04-24 01:23:06 +03:00
Hakan SevenandClaude Sonnet 4.6 0a291c877b feat: A4 landscape default paper, white paper area on dark desk
- paper_limits() falls back to A4 landscape (297×210mm) even when no
  Layout object exists in the document
- paper_bg_color default changed to white [1,1,1,1] (paper surface color)
- PaperCanvas::draw() fills canvas with dark desk color first, then draws
  the paper area rectangle in paper_bg_color so the sheet is clearly
  visible against the desk background
- view.rs container background uses the fixed desk color instead of
  paper_bg_color so it no longer conflicts with the paper-surface color
- BACKGROUND RESET for paper space now resets to white instead of dark gray
- Removed unused PaperSheet variant, paper_sheet() constructor,
  build_paper_sheet_primitive() and associated match arms (dead code
  after 2D canvas replacement)

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-04-23 14:05:07 +03:00
Hakan SevenandClaude Sonnet 4.6 070ad1f9c5 feat: add Report/About/Changelog buttons to Support ribbon group
- REPORT opens GitHub new-issue page
- ABOUT opens a dialog window with version, OS and arch info + Copy Info button
- CHANGELOG opens GitHub releases page
- Fix Windows build: add windows-sys as target-specific dependency for PRINT command

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-04-22 22:22:33 +03:00
Hakan SevenandClaude Sonnet 4.6 08b9a21d31 feat: add missing Annotate tab commands and icons
New dimension commands: QDIM, DIMEDIT, DIMTEDIT, DIMBREAK, DIMSPACE,
DIMJOGLINE with full command workflows and SVG icons.

New multileader commands: MLEADERADD, MLEADERREMOVE, MLEADERALIGN,
MLEADERCOLLECT with entity injection pattern for in-place editing.

Updated annotate ribbon: all tools exposed across Text, Dimensions,
Leaders, Tables, Markup, and Annotation Scaling groups. Added STYLE,
FIND, DIMSTYLE shortcut buttons.

Added `inject_picked_entity` to the CadCommand trait for commands that
need a cloned copy of the picked entity to modify (DIMTEDIT, MLEADERADD,
MLEADERREMOVE). Sentinel-based dispatch in cmd_result.rs handles
DIMBREAK, DIMSPACE, DIMJOGLINE, MLEADERALIGN, and MLEADERCOLLECT.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-04-09 03:26:47 +03:00
Hakan SevenandClaude Sonnet 4.6 781bd186ee chore: fix all compiler warnings
- cmd_result.rs: remove unused Point3 and Rad imports (SWEEP block)
- scene/mod.rs: remove unused Solid3D struct import
- commands.rs: drop unnecessary `mut` on new_entities (REFCLOSE block)
- refedit.rs: annotate insert_handle with #[allow(dead_code)]

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-04-08 22:28:31 +03:00
Hakan SevenandClaude Sonnet 4.6 b24e0c5da9 feat: STEPOUT command — export 3D meshes to STEP AP203
Adds STEPOUT / STPOUT / EXPORTSTEP command that exports all tessellated
Solid3D / Region / Body meshes to an ISO 10303-21 (STEP AP203) file.

Each triangle is encoded as a minimal ADVANCED_FACE with a PLANE surface
and CLOSED_SHELL topology — sufficient for import into all major CAD systems.
A file-save dialog picks the output path; the command line reports success or
errors. Requires at least one tessellated solid in the drawing.

Closes ROADMAP 14.10.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-04-08 22:23:58 +03:00
Hakan SevenandClaude Sonnet 4.6 f515b556c7 feat: PRINT command — send layout to system printer via lp/lpr
The PRINT command renders the current layout to a temporary PDF (reusing
the existing PDF export pipeline) and dispatches it to the OS default
printer:
  - Linux/macOS: `lp` (CUPS) with `lpr` as fallback.
  - Windows: ShellExecute "print" verb (compiled-in, unused on Linux).

PLOT and EXPORT still open the save-file dialog as before.
Status messages are shown in the command line during the async job.

Closes ROADMAP 1.8.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-04-08 22:21:50 +03:00
Hakan SevenandClaude Sonnet 4.6 ff39759d02 feat: VPORTS preset viewport configurations (2H / 2V / 4 / SINGLE)
VPORTS now accepts a layout subcommand in paper-space:
  VPORTS 2H     — two viewports side by side (horizontal split)
  VPORTS 2V     — two viewports stacked (vertical split)
  VPORTS 4      — 2×2 grid of four equal viewports
  VPORTS SINGLE — one full-page viewport

Paper dimensions are read from PlotSettings (fallback A4 landscape).
Existing user viewports are replaced and each new viewport is
auto-fitted to show model-space content.
Bare VPORTS still lists existing viewports.

Closes ROADMAP 8.5.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-04-08 22:19:08 +03:00
Hakan SevenandClaude Sonnet 4.6 67b5f5e3d5 feat: Keyboard Shortcuts panel + SHORTCUTS command
Opens a reference panel listing all built-in keyboard shortcuts
(F3-F12, Ctrl+N/O/S/Z/C/X/V, etc.) and any user-defined overrides.

SHORTCUTS LIST         — open the panel
SHORTCUTS SET <k> <c>  — add/update a custom shortcut label
SHORTCUTS CLEAR <k>    — remove a custom entry

Custom shortcuts are stored in app state (runtime only) and shown
in the panel alongside the hardcoded bindings.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-04-08 18:34:10 +03:00
Hakan SevenandClaude Sonnet 4.6 e36fafe6df feat: COLORSCHEME command — runtime UI theme/color-scheme switching
Adds active_theme: Theme field to app state and wires the daemon's
.theme() callback to use it dynamically. COLORSCHEME <name> switches
among all 19 built-in iced themes (Dark, Light, Dracula, Nord, Tokyo
Night, Gruvbox, Kanagawa, Moonfly, Nightfly, etc.).

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-04-08 18:31:09 +03:00
Hakan SevenandClaude Sonnet 4.6 85f9b930a2 feat: Layout Manager GUI (LAYOUTMANAGER / LAYOUTPANEL command)
Panel overlay showing all layouts with their active status.
Supports: select, rename, new, delete, reorder (◀▶), set current.
Also adds Scene::swap_layout_order() for tab-order resequencing.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-04-08 18:28:30 +03:00
Hakan SevenandClaude Sonnet 4.6 b8d15e5155 feat: Plot Style Table Editor GUI (PLOTSTYLEPANEL / STYLESMANAGER)
Opens a panel overlay showing all 255 ACI entries with their current
overrides (color, lineweight, screening). Allows editing entries
interactively, creating a new identity table when none is loaded,
and saving the modified table back to a CTB/STB file.

Commands: PLOTSTYLEPANEL, PLOTSTYLEEDITOR, STYLESMANAGER

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-04-08 18:19:48 +03:00
Hakan SevenandClaude Sonnet 4.6 1fceec92ea feat: MLEADERSTYLE command — create and manage MultiLeader styles
Stores MultiLeaderStyle objects in document.objects. Supports:
  MLEADERSTYLE LIST — list all styles
  MLEADERSTYLE NEW <name> — create a new style
  MLEADERSTYLE SET <name> <prop> <val> — edit text_height,
    arrowhead_size, landing_distance, landing_gap
  MLEADERSTYLE CURRENT [<name>] — get/set active style

Active style name tracked per-tab in active_mleader_style.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-04-08 18:13:21 +03:00
Hakan SevenandClaude Sonnet 4.6 1d349c53af feat: LOFT command — ruled-surface loft through multiple cross-sections
Picks 2+ profile entities (closed or open wires), builds ruled shells
between consecutive pairs via builder::try_wire_homotopy, caps closed
ends with planar faces, and tessellates the result into a Solid3D mesh.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-04-08 18:08:53 +03:00