Commit graph

196 commits

Author SHA1 Message Date
Hakan Seven
578dd51af4 fix: set A4 landscape limits on initial Layout1 at document creation
acadrust initialises every Layout with 12×9 imperial defaults; override
all non-Model layouts to 297×210mm in new_drawing() so the first paper
tab opens at A4 size, consistent with layouts added later.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 14:23:38 +03:00
Hakan Seven
f63858876d fix: align white paper fill with entity borders
- paper_entity_extents() computes the bounding box of actual DXF entities
  so the white fill always matches the drawn title-block / frame borders,
  regardless of whether Layout min/max_limits match entity positions
- Falls back to paper_limits() (→ A4 297×210) when layout has no entities
- Removed paper_boundary_wire: the white fill now acts as the visual paper
  edge so the near-white wire (invisible on white) was redundant
- LayoutCreate sets limits to A4 landscape immediately after add_layout()
  to override acadrust's imperial default (12×9)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 14:21:03 +03:00
Hakan Seven
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 <noreply@anthropic.com>
2026-04-23 14:05:07 +03:00
Hakan Seven
fcc29de469 feat: inline MSPACE viewport overlay on 2D paper canvas
- viewport_screen_rect now mirrors PaperCanvas::draw()'s camera-based
  to_px transform instead of using a fixed paper-limits scale, so the
  3D overlay lands exactly over the drawn viewport border at any zoom/pan

- blue border frame (stack layer above the shader) makes the active
  viewport boundary always visible even when it fills the canvas

- space-mode pill in MSPACE now dispatches LayoutSwitch("Model") so
  clicking it jumps to full Model Space instead of just exiting to PSPACE

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 13:57:34 +03:00
Hakan Seven
459b525ffe feat: replace paper-space shader with 2D Iced canvas widget
Paper space is now rendered as a 2D vector canvas (iced::widget::canvas)
instead of a 3D shader widget.  This allows direct interaction with
paper-space entities (title blocks, viewport borders, annotations)
without needing to enter MSPACE first.

Changes:
- src/scene/paper_canvas.rs: new PaperCanvas<'a> canvas::Program that
  renders paper wires (with linetype dashes), solid/gradient hatch fills,
  and wipeout backgrounds using the paper camera's orthographic transform.
- Scene: three new public helpers (paper_canvas_wires, paper_canvas_hatches,
  paper_canvas_wipeouts) feed the canvas with the same data the old shader
  used, including inactive viewport projections and interim/preview wires.
- view.rs: paper_canvas_view() now wraps PaperCanvas instead of
  shader(ViewportPane::paper_sheet(…)).  The PaperViewportPane 3D shader
  overlay for the active MSPACE viewport is unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 09:48:53 +03:00
Hakan Seven
1c0520e4e4 fix: correct CPU projection axes to match GPU look_at_rh convention
viewport_content_wires() computed view_right via world_z × view_direction
(cross-product). This gives the OPPOSITE sign to the right vector that
look_at_rh produces for views with a Y component (FRONT/BACK views):

  GPU look_at_rh:  screen_right = f × up = (−vd) × (rot*Y) = rot*X
  Old CPU formula: screen_right = Z × vd  ← opposite sign for FRONT/BACK

The mismatch caused the paper-space projection to appear mirror-flipped
after panning/rotating in MSPACE.

Fix: use camera_for_viewport() to obtain the exact same rotation
quaternion the GPU uses, then derive both axes from it:
  view_right = rotation * X
  view_up    = rotation * Y

Also replaces the perspective depth dot-product (mp · vd) with
mp · (rotation*Z) so the depth direction is consistent too.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 09:28:54 +03:00
Hakan Seven
c2df63c4cc feat: add clickable space-mode button to status bar
Replaces the static MODEL/LAYOUT pill with an interactive button that
shows and toggles the current editing context:

  Model tab     → "MODEL"  (non-clickable, informational)
  Layout PSPACE → "PAPER"  (click → MspaceCommand: enter MSPACE)
  Layout MSPACE → "MODEL"  (click → ExitViewport: return to PSPACE)

Highlights in blue when in MSPACE to signal active model editing.
Mirrors the AutoCAD status-bar convention for MODEL/PAPER switching.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 09:18:01 +03:00
Hakan Seven
2c5405aa49 fix: correct MSPACE orbit and pan direction
orbit_active_viewport was writing cam.rotation*Z directly to
view_direction, but yaw_pitch_to_quat(y,p)*Z has its Y component
negated relative to the snap convention: (cos(p)*sin(y), -cos(p)*cos(y),
sin(p)) vs (cos(p)*sin(y), +cos(p)*cos(y), sin(p)).  This caused
camera_for_viewport to reconstruct yaw = π - original_yaw, making every
orbit appear reversed.  Fix: negate Y when writing view_direction back.

pan_active_viewport was using the paper-space camera to convert screen
pixels to model-space delta.  This gives wrong pan axes for tilted
MSPACE views (e.g. front/side views where cam_up is Z, not Y).  Fix:
use camera_for_viewport so the pan axes match the 3-D view orientation,
and update all three view_target components (X/Y/Z) for tilted views.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 09:10:55 +03:00
Hakan Seven
f176f7c80a fix: correct ViewCubeSnap and MSPACE orbit to write viewport entity
- Add orbit_active_viewport(), snap_active_viewport_to_angles(),
  active_view_rotation_mat(), active_viewport_yaw_pitch() helpers so
  navigation gestures modify the DXF viewport entity's view_direction
  instead of the paper-space camera.
- Fix "already there → flip opposite" check: the previous code used
  rot * Vec4::W (always (0,0,0,1) for a rotation matrix); now reads
  (yaw, pitch) directly from camera_for_viewport() via the new helper.
- MSPACE right-drag orbit early-returns after writing the viewport
  entity, preventing the paper-space camera from also being modified.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 08:53:30 +03:00
Hakan Seven
7e0e892bcc chore: remove VIEWPORT_WIDGET_PLAN.md as refactoring steps are complete 2026-04-23 03:25:15 +03:00
Hakan Seven
97dbd80c93 feat: render active MSPACE viewport as a true 3D widget in paper space
When a paper-space viewport is activated (double-click / MSPACE command),
it is now rendered through its own dedicated PaperViewportPipeline rather
than the CPU-projection approach used for inactive viewports.

Architecture:
- PaperSheet widget (full-canvas): renders paper entities + CPU-projected
  content of all viewports *except* the active one.
- PaperViewportPane widget (Fixed w×h, positioned at viewport screen rect):
  renders the active viewport with a true 3D camera derived from the
  viewport's view_direction/view_target/view_height.

PaperViewportPipeline is a newtype of Pipeline.  Having a distinct type
gives it its own Iced storage entry (keyed by TypeId), preventing the
shared prepare() overwrite that broke the earlier per-viewport approach.

Changes:
- render.rs: PaperViewportPipeline, PaperViewportPrimitive newtypes;
  build_active_viewport_primitive(); build_paper_sheet_primitive() now
  excludes active_viewport from CPU projection.
- viewport_pane.rs: PaperViewportPane<'a> with shader::Program impl.
- mod.rs: viewport_content_wires() gains exclude_vp parameter;
  viewport_screen_rect() is no longer dead code.
- view.rs: paper_canvas_view() overlays PaperViewportPane when MSPACE
  is active.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 03:19:15 +03:00
Hakan Seven
d1d4bb3d02 fix: restore paper-space viewport rendering as single full-canvas widget
Iced 0.14 batches all shader prepare() calls before any render() calls.
Multiple ViewportPane widgets sharing the same Pipeline type overwrite
each other's GPU buffers, causing the PaperSheet layer (full-canvas) to
render the last viewport's model content — appearing full-screen.

Fix: paper_canvas_view() now renders a single full-canvas PaperSheet
widget. build_paper_sheet_primitive() is updated to include model-space
content projected through each viewport's view matrix (via
viewport_content_wires()), restoring the original working behaviour.

ViewportPane::Paper mode and viewport_screen_rect() are kept with
#[allow(dead_code)] — a per-viewport wgpu sub-renderer that accumulates
data across frames could revive them in the future.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 03:02:01 +03:00
Hakan Seven
592e3da6ac docs: mark Steps 5-6 complete in ViewportPane plan
Both items were already implemented prior to this commit:
- MSPACE mouse routing (double-click/pan/zoom/Escape) was fully wired
  through the existing viewport_mouse overlay and scene helpers.
- Per-viewport frozen layer filtering uses matching Handle values from
  the same CadDocument, confirmed correct in model_wires_for_viewport().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 02:47:42 +03:00
Hakan Seven
da9fafc0f8 feat: introduce ViewportPane widget for unified model/paper rendering
- Remove Scene: shader::Program<Msg> impl; all GPU rendering now goes
  through ViewportPane which supports three modes:
    Model      — full model-space view (unchanged behaviour)
    PaperSheet — paper-space entities only, using the paper camera
    Paper      — model content through a specific viewport's own camera

- Add Scene helper methods (render.rs):
    build_primitive / build_paper_sheet_primitive / build_viewport_primitive
    update_viewcube_state / viewcube_mouse_interaction

- Add Scene helpers (mod.rs):
    paper_sheet_wires()        — paper entities without viewport projection
    camera_for_viewport()      — derive Camera from Viewport entity data
    model_wires_for_viewport() — model wires filtered by per-viewport frozen layers
    viewport_screen_rect()     — paper-space → pixel rect mapping

- Add paper_canvas_view() in view.rs:
    Stack of PaperSheet + one Paper widget per Viewport entity,
    positioned with Space offsets from viewport_screen_rect()

- Update VIEWPORT_WIDGET_PLAN.md: mark Steps 1–4 done, document remaining work

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 02:18:41 +03:00
Hakan Seven
de04b7e351 chore: bump version to 0.1.5
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 22:23:00 +03:00
Hakan Seven
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 <noreply@anthropic.com>
2026-04-22 22:22:33 +03:00
Hakan Seven
62fbaf5da4 fix: hide block definition entities from viewport
Block-definition geometry (entities stored inside named blocks) was
leaking into the viewport when DXF files omit the owner-handle group
code (330) on block-content entities.

The fix tightens `belongs_to_visible_block`: when `owner_handle` is
null, the current layout block-record's `entity_handles` list is used
as the authoritative allow-list before falling back to the older
"not-in-any-other-block" heuristic.  This ensures block definitions
are never rendered directly, only when referenced via an INSERT.

Bumps version to 0.1.4.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 22:03:32 +03:00
Hakan Seven
e2f5715de8 fix: correct arc sweep direction for reversed normals and mirrored blocks
- Arc rendering now respects the normal vector: when normal.z < 0 the
  midpoint is placed on the clockwise side so the curve sweeps the right way
- Removed spurious .to_radians() / .to_degrees() round-trips in arc.rs
  (angles are already stored in the unit the trig functions expect)
- apply_grip and apply_transform use consistent angle units
- normalize_insert_entity no longer converts arc angles; the old conversion
  was only needed by the now-removed .to_radians() call in to_truck
- Added fix_mirrored_arc: swaps arc start/end angles when the INSERT has a
  mirrored scale (x_scale * y_scale < 0) so exploded arcs curve correctly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 21:48:21 +03:00
Hakan Seven
a255b99863 docs: add COMMANDS.md and update ROADMAP.md in English
- Add COMMANDS.md: full CAD command reference (256 commands across 11
  categories) with implemented/partial/missing status for each
- Update ROADMAP.md to English, remove external product name references

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 20:06:35 +03:00
Hakan Seven
a879c9d878 docs: add ROADMAP.md with unimplemented ribbon commands
Lists 33 stub commands across Insert, View, Manage, and Annotate tabs
with descriptions and Low/Medium/High complexity estimates.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 19:49:06 +03:00
Hakan Seven
fce611d782 feat: redesign Manage tab to match reference layout
- Add Customization group: User Interface (CUI), Tool Palettes (large),
  Import, Export, Edit Aliases dropdown (small)
- Add Cleanup group: Find Non-Purgeable Items (large), Purge, Overkill, Audit (small)
- Add 8 new SVG icons for all new commands

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:27:40 +03:00
Hakan Seven
ef988c20a3 feat: redesign Insert tab and fix all warnings
- Redesign Insert ribbon tab with 6 groups matching screenshot layout:
  Reference (Attach/Clip/Adjust large + Underlay Layers/Frames/Snap small),
  Point Cloud (Attach), Block (Multi-View Block/Insert large + Create/Edit/Base small),
  Attributes (Define/Edit large + Manage/Sync small),
  Import (Import/Land XML), Content (Content Browser/Design Center)
- Remove Primitives group and dead box_prim/clear/cylinder/sphere modules
- Fix all compiler warnings with #[allow(dead_code)] on unused-but-intentional items

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 12:44:31 +03:00
Hakan Seven
e3bce16545 feat: redesign View tab and fix Annotate/tab order
- Redesign View ribbon tab with 8 groups matching AutoCAD layout:
  Viewport Tools (UCS Icon, ViewCube, Navigation Bar),
  Navigate, Model Viewports (Viewport Configuration, Named, Join, Restore),
  Visual Style (dropdown), Projection, Preset,
  Palettes (Tool Palettes, Properties, Sheet Set Manager),
  Interface (File Tabs, Layout Tabs, Tile Horiz/Vert, Cascade)
- Add Extract Data and Link Data tools to Annotate → Tables group
- Fix tab order to Home → Insert → Annotate → View → Manage via build.rs PRIORITY list
- Add 17 new SVG icons for all new commands

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 12:25:15 +03:00
Hakan Seven
c8991bcc5a fix: make Wipeout and RevCloud large tools in Markup group
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 03:47:22 +03:00
Hakan Seven
bd68114bde feat: add style selector comboboxes to Annotate ribbon tab
New StyleComboGroup RibbonItem renders a dropdown combobox for selecting
text style, dimension style, multileader style, or table style. Ribbon
groups in the Annotate tab now match the reference layout: each group
has a large tool on the left and a style combobox with tool rows on the
right.

Each combobox shows the active style name, opens a scrollable item list
on click, and has an optional "Manage…" row that fires the style manager
command (STYLE / DIMSTYLE / MLEADERSTYLE / TABLESTYLE).

Style state is synced from the document on every layer refresh via
sync_ribbon_styles(). RibbonStyleChanged message propagates selections
back to the acadrust document header and the active_mleader_style field.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 03:38:23 +03:00
Hakan Seven
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 <noreply@anthropic.com>
2026-04-09 03:26:47 +03:00
Hakan Seven
510bcf11e5 feat: redesign Annotate ribbon tab with proper groups and SVG icons
Added 15 SVG icons for all annotation tools (dimensions, leaders,
table, wipeout, revision cloud, tolerance, ddedit).

Annotate ribbon now has 6 groups matching standard CAD layout:
- Text: MText (large dropdown) + Text + Edit Text
- Dimensions: Linear (large dropdown with 6 types) + Continue + Baseline + Tolerance
- Leaders: Multileader (large dropdown) + Leader
- Tables: Table (large)
- Markup: Wipeout + Rev Cloud
- Annotation Scaling: Scale List, Add Scale, Scale Edit, Sync Scales

Added pub tool() + ICON to all annotate tools that were missing them
(aligned_dim, diameter_dim, dim_continue, dim_baseline, table_cmd,
tolerance_cmd, ddedit), and to home/draw/wipeout and revcloud.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 03:03:08 +03:00
Hakan Seven
fe4f9ca844 refactor: move all dialog UIs to dedicated files under src/ui/
Each dialog window (Page Setup, DimStyle, TextStyle, TableStyle,
MLineStyle, PlotStyle, Layout Manager, Shortcuts) is now a proper
window-filling layout in its own src/ui/<dialog>.rs file.

Pattern: toolbar strip at top + vertical separator + scrollable
content filling the rest — no modal card, no backdrop, no stack[].
Matches the existing Layer Manager window pattern.

Removed ~1600 lines of old overlay functions from view.rs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 22:56:51 +03:00
Hakan Seven
888095cc3e refactor: convert all overlay dialogs to separate OS windows
Every dialog panel that previously rendered as an in-viewport overlay is
now opened as its own OS window, matching the behaviour of the Layer
Properties Manager:

  • Page Setup           (520×460, non-resizable)
  • Text Style           (620×460)
  • Table Style          (620×420)
  • Multiline Style      (620×420)
  • Layout Manager       (640×320)
  • Plot Style Editor    (780×540)
  • Dimension Style Mgr  (720×560)
  • Keyboard Shortcuts   (720×520)

Changes:
  - mod.rs: replace *_open: bool fields with *_window: Option<window::Id>;
    add window IDs to OsWindowClosed tracker; add per-window title strings.
  - update.rs: Open handlers call window::open(); if already open, call
    window::gain_focus() instead of reopening. Close handlers call
    window::close(). OsWindowClosed clears all panel window IDs.
  - view.rs: each window_id is matched at the top of view() and returns
    the panel content directly. All overlay let-bindings and stack![]
    references removed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 22:36:28 +03:00
Hakan Seven
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 <noreply@anthropic.com>
2026-04-08 22:28:31 +03:00
Hakan Seven
ea5fd7c9d9 docs: update ROADMAP to v0.1.4 — mark all newly completed features
Closes:
  1.8  Physical printer (PRINT command)
  2.13 Region / Body / Wire / Silhouette entity render
  3.2  Region, Body, Wire/Silhouette, Ole2Frame entity support
  8.5  VPORTS preset viewport splitting (2H / 2V / 4 / SINGLE)
  11.6 VPLAYER per-viewport layer freeze/thaw (previously 🔧)
  14.10 STEP AP203 export (STEPOUT command)

Remaining open items: failsafe DWG parse, Boolean 3D ops, toolbar
customization — all blocked on external library support.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 22:25:03 +03:00
Hakan Seven
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 <noreply@anthropic.com>
2026-04-08 22:23:58 +03:00
Hakan Seven
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 <noreply@anthropic.com>
2026-04-08 22:21:50 +03:00
Hakan Seven
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 <noreply@anthropic.com>
2026-04-08 22:19:08 +03:00
Hakan Seven
28f5c84b09 feat: Solid3D wire fallback render + Ole2Frame placeholder
- When SAT tessellation yields no mesh (binary SAB or unsupported ACIS
  geometry), render the pre-computed edge-wire polylines stored in
  Solid3D / Region / Body entities as a visible line fallback.
- Ole2Frame entities now render a bounding rectangle with diagonal X
  instead of an invisible stub — marks embedded OLE objects in the
  viewport.

Closes ROADMAP 2.13 (partial), 3.2 (Ole2Frame).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 22:16:58 +03:00
Hakan Seven
5cf7a19ca8 feat: Region and Body entity tessellation + render
Refactors solid3d_tess to share tessellate_sat() across Solid3D,
Region (2D planar ACIS body), and Body (3D ACIS body).
populate_meshes_from_document() and add_entity() now tessellate
all three entity types into GPU MeshModels when ACIS SAT data
is available.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 18:37:24 +03:00
Hakan Seven
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 <noreply@anthropic.com>
2026-04-08 18:34:10 +03:00
Hakan Seven
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 <noreply@anthropic.com>
2026-04-08 18:31:09 +03:00
Hakan Seven
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 <noreply@anthropic.com>
2026-04-08 18:28:30 +03:00
Hakan Seven
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 <noreply@anthropic.com>
2026-04-08 18:19:48 +03:00
Hakan Seven
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 <noreply@anthropic.com>
2026-04-08 18:13:21 +03:00
Hakan Seven
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 <noreply@anthropic.com>
2026-04-08 18:08:53 +03:00
Hakan Seven
063a1d5be1 feat: SWEEP command — sweep profile along Line/Polyline path
Picks a profile (closed or open 2D entity) then a path entity
(Line or LwPolyline). For Line paths uses tsweep along the line
vector; for Polyline paths uses start→end as translation direction.
Closed profiles produce a capped Solid; open profiles a Shell.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 18:07:00 +03:00
Hakan Seven
6fa3157e72 feat: OBJ mesh import (IMPORTOBJ / OBJIMPORT command)
Parses Wavefront OBJ files (v/vn/f, fan-triangulation, face normals
fallback) and inserts the result as a Solid3D placeholder + MeshModel
visible in the 3D viewport.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 12:59:27 +03:00
Hakan Seven
549ae38459 feat: BOX, SPHERE, CYLINDER primitives + EXTRUDE / REVOLVE commands
BOX, SPHERE, and CYLINDER build truck topology solids and tessellate
them into MeshModels stored alongside a Solid3D placeholder entity so
the GPU mesh pipeline renders them immediately.

EXTRUDE picks any closed 2D profile (Circle, LwPolyline, etc.),
attaches a planar face via try_attach_plane, and translational-sweeps
it (tsweep Face → Solid) along Z by the given height.

REVOLVE picks a profile, two axis points, and an angle (default 360°),
then rotational-sweeps the wire (rsweep) around the axis.

Three new CmdResult variants drive the operations:
  CommitSolid3D, ExtrudeEntity, RevolveEntity.

Scene::layer_color() added to retrieve the active layer's RGBA color.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 12:55:28 +03:00
Hakan Seven
a773a1a1f1 feat: REFEDIT / REFCLOSE — in-place block reference editing
REFEDIT picks an INSERT, extracts the block entities into model space
with the INSERT transform applied (translate + rotate + uniform scale),
and enters an editing session.  Any normal modify command works on the
temporary entities.

REFCLOSE SAVE applies the inverse transform, replaces the block
definition, and rebuilds all derived caches (hatch/image/mesh), so
every INSERT of that block reflects the edits immediately.
REFCLOSE DISCARD removes the temp entities without changing the block.

Non-uniform-scale inserts are rejected with an error message.
RefEditSession is stored on DocumentTab; undo snapshots bracket the
begin and close operations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 12:40:19 +03:00
Hakan Seven
42048362e2 fix: MSAA resolve no longer overwrites widget backgrounds
MSAA and depth textures are now sized to the shader widget's clip
bounds instead of the full surface. The resolve writes to a matching
clip-sized intermediate texture; a blit pass (blit.wgsl, viewport
trick) then copies the result to the exact clip region of the surface
target, leaving all other widgets untouched.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 12:20:47 +03:00
Hakan Seven
c12b30ad3d feat: 4× MSAA anti-aliasing for main drawing pipelines
All main render pipelines (wire, hatch, image, mesh) now use 4×
multisampling. Drawing passes render to a dedicated MSAA color buffer;
a final empty resolve pass transfers the anti-aliased result to the
iced surface target. The ViewCube renders post-resolve at 1× to avoid
pipeline incompatibility. Depth buffer also upgraded to 4× MSAA.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 00:52:38 +03:00
Hakan Seven
25b91bc09e feat: STL export (STLOUT / EXPORTSTL command)
Exports all tessellated 3D mesh models in the current drawing to a
binary STL file via a save-file dialog. Normals are taken from the
MeshModel where available, otherwise computed from triangle vertices.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 00:46:05 +03:00
Hakan Seven
9ede70ef1c feat: 3D ARRAY (ARRAY3D / 3DARRAY command)
Three-dimensional rectangular array: prompts for rows, columns, levels
and their respective spacings, then generates copies translated along
X (columns), Z (rows in drawing plane), and Y (levels / height).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 00:43:21 +03:00