Commit Graph
22 Commits
Author SHA1 Message Date
Hakan Seven 559cd76369 feat(grip): value-prompt actions Lengthen/Radius/Arc Length
Lengthen / Radius / Arc Length need a number after the pick. Stash
`grip_pending` on the picked action, push prompt to command line,
route next `CommandSubmit` parse into `apply_grip_menu_value`.
Escape cancels.

- `Grippable::grip_menu_value_prompt` returns label when action
  wants value; `apply_grip_menu_value` runs the edit. Dispatched
  via `EntityTypeOps`.
- Line: Lengthen extends either endpoint along line direction.
- Arc: Radius sets radius; Arc Length redrives end angle from
  `value / radius`; Lengthen extends start / end angle the same
  way.
2026-05-29 14:58:35 +03:00
Hakan Seven 6c1462932d feat(grip): multi-functional hover popup menu
Phase 2 of the grip overhaul: when the cursor dwells on a selected
entity's grip the overlay opens a popup menu with entity-specific
options (Stretch / Add Vertex / Remove Vertex / Convert to
Arc-Line / …). Picking an item dispatches `apply_grip_menu`; the
default `Stretch` entry is a no-op that lets the user click the
grip to start the normal drag.

- `GripMenuItem` + `GripMenuAction` (full vocabulary covering
  stretch, add/remove vertex, convert to arc/line, reverse arrows,
  text-position variants, hatch parameters, tangent direction).
- `Grippable` trait gains `grip_menu` + `apply_grip_menu` with
  trait-default `Stretch`-only impls so every existing entity gets
  the popup for free.
- `EntityTypeOps` dispatches both methods across the same entity
  list as the existing grip / property machinery.
- `OpenCADStudio` carries `grip_hover` (dwell tracker) +
  `grip_popup` (open menu). `update_grip_hover` runs from
  `ViewportMove`: hit-tests grips, refreshes the dwell timer, and
  opens the popup after 600 ms. Cursor drift past 80 px or a grip
  click dismisses it.
- `view.rs` paints the popup as an absolute-positioned column of
  buttons at the grip's screen anchor; each button publishes
  `Message::GripMenuPick(idx)`.
- `LwPolyline` overrides `Grippable` manually (skips the standard
  macro) so its vertex grip exposes Add/Remove Vertex and its
  segment-midpoint grip exposes Add Vertex + Convert to Arc/Line.
  `apply_grip_menu` performs the edits: vertex insertion at the
  chord midpoint inheriting the previous bulge, vertex removal,
  and bulge toggle for the arc/line conversion.
2026-05-29 09:30:54 +03:00
Hakan SevenandClaude Opus 4.7 9b5073752d refactor(entities): collapse trait wrapper boilerplate via macro
Every entity file ended with the same three-trait wrapper block:

    impl Grippable for T {
        fn grips(&self) -> Vec<GripDef> { grips(self) }
        fn apply_grip(&mut self, ...) { apply_grip(self, ...) }
    }
    impl PropertyEditable for T { ... }
    impl Transformable for T { ... }

— 23 lines of pure delegation around five same-named free functions.

Replace with `crate::impl_entity_basics!(T);` (a macro in
entities/traits.rs that expands to the three trait impls).

Applied where the file already follows the free-fn delegation
convention (Arc, Circle, Ellipse, Insert, Leader, Line, LwPolyline,
MultiLeader, Ole2Frame, Point, Spline, Viewport). Files that inlined
the trait method bodies directly (Ray, XLine, Shape, Solid, Tolerance,
MLine, Mesh, Solid3D/Region/Body, Table, RasterImage, Wipeout,
Underlay, Hatch, Polyline, Polyline2D, Polyline3D, Dimension) left
alone — they already skip the indirection. Text/MText/Attribute use
the with-text-style flavour and will move once that variant is needed
beyond the existing two manual impls.

A second macro `impl_entity_basics_with_text_styles!` is included for
the text-like flavour but no entity uses it yet.

Net: -204 lines.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 17:16:06 +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 <noreply@anthropic.com>
2026-05-23 23:30:34 +03:00
Hakan SevenandClaude Opus 4.7 64d8b2117d refactor(entities): macro-ize EntityTypeOps dispatch
Each of the five dispatch functions in `entities/traits.rs` was a
hand-written `match self { EntityType::Line(e) => ..., EntityType::Arc(e)
=> ..., ... }` block listing ~35 variants. Adding a new entity meant
adding five match arms across the file.

Replace with a `dispatch!` macro that takes `(self, |e| body, [variant
list], _ => default)`. Each dispatch function keeps its own variant
list (the supported sets differ per trait), but the per-arm
boilerplate is gone.

File shrinks from 386 to 145 lines. Adding a new entity now means
adding one identifier to one (or more) of the variant lists.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 23:18:22 +03:00
Hakan SevenandClaude Opus 4.7 b413fe0efe refactor(tess): rename LegacyTess → FallbackTess
The trait isn't deprecating anything — it carries the path entities
take when they're not covered by the truck topology pipeline
(Viewport, Insert, Hatch outline, Ole2Frame). "Fallback" names the
purpose; "Legacy" implied retirement that isn't actually on the
roadmap.

Same rename for LegacyGeometry → FallbackGeometry,
legacy_geometry() → fallback_geometry().

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 23:16:57 +03:00
Hakan SevenandClaude Opus 4.7 aadb64860d refactor(tess): move per-entity tessellation into entities/
Each entity's tessellation now lives alongside its definition in
entities/*.rs, attached to the entity type via a local trait:

  LegacyTess     — Viewport / Insert / Hatch / Ole2Frame
                   (fallback path for entities not on the truck pipeline)
  LeaderTess     — Leader
  MultiLeaderTess — MultiLeader
  DimensionTess  — Dimension (carries its dim-only helpers too:
                   ~1700 lines of dim_geometry, dim_text_*, format_*,
                   tolerance, suppression, etc.)

scene/tessellate.rs keeps only the cross-entity dispatcher plus the
shared dim machinery reused by leader/multileader/dimension
(ArrowKind, DimGeom, append_arrow, arrow_from_block, add_segment,
add_polyline, normalized_or, push_tri, color_or_inherit, entity_z,
offset_snap_pts). Cross-entity arc helpers + aci_to_rgba moved to
scene/tess_util.rs.

scene/tessellate.rs shrinks from ~3300 to 809 lines. Compile clean,
all 9 tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 23:12:27 +03:00
Hakan SevenandClaude Opus 4.7 6110da99a5 feat(entities): surface remaining 3D fields + add Mesh render path
Closes out the 3D-entity audit. Mesh (modern SubD mesh) gained a full
render impl since it had no TruckConvertible / Grippable / PropertyEditable
hookup at all — it was silently dropped on open. Remaining mesh-style
entities pick up the few fields the parser populated:

- Mesh (SubD): wireframe + face-fan fill_tris rendering, per-vertex grips,
  Properties panel surfaces version, subdivision_level, blend_crease,
  creased-edge count, vertex / face / edge counts; wired into the
  Transformable / Grippable / PropertyEditable / TruckConvertible
  dispatch in entities/traits.rs
- Polyline3D: smooth_type, default_start_width, default_end_width,
  mesh_m_count, mesh_n_count, smooth_m_density, smooth_n_density
  (widths editable)
- PolygonMesh: smooth_type, m/n_smooth_density, elevation, normal
- PolyfaceMesh: smooth_surface, seqend_handle, elevation, normal,
  thickness

Solid3D / Region / Body's uid + silhouettes + history_handle were
included in the prior 2D commit since they share the same file.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 21:35:14 +03:00
Hakan ca07268c7c cargo fmt 2026-05-12 10:36:15 +03:00
Hakan 534e4ff26b feat: implement Grippable and PropertyEditable traits for Solid3D, Region, and Body; add snap points and geometry properties 2026-05-06 10:00:37 +03:00
Hakan SevenandClaude Sonnet 4.6 f000a8acfb feat: add OLE2Frame interactivity + fix Shape rotation from DXF
OLE2Frame: full TruckConvertible/Grippable/PropertyEditable/Transformable
impls in src/entities/ole2frame.rs — grips on corners + center, properties
panel, translate/scale transforms.

Shape: rotation (DXF code 50) now converted degrees→radians on load in
fix_dxf_dimension_rotations(), matching Dimension and Attribute behaviour.

All ❌ gaps resolved. Remaining: Viewport GPU scissor, LWPolyline plinegen.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 20:12:44 +03:00
Hakan SevenandClaude Sonnet 4.6 cc314e75fc feat: Shape entity support (render + grips + props + transform)
- src/entities/shape.rs: diamond marker at insertion point (SHX glyphs
  cannot be rendered without the binary .shx file, so a placeholder is used)
- Grips: single insertion-point grip
- Properties: Name, Style (read-only), Insert X/Y/Z, Size, Rotation
- Transformable: translate, mirror, scale, rotate
- Registered in entities/mod.rs, entities/traits.rs, app/commands.rs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 23:30:27 +03:00
Hakan SevenandClaude Sonnet 4.6 6f19b4fd81 feat: add Underlay entity support (PDF/DWF/DGN)
- New src/entities/underlay.rs: TruckConvertible (clip boundary polygon
  or cross marker), Grippable (insertion + boundary vertex grips),
  PropertyEditable (position, scale, rotation, contrast, fade, flags),
  Transformable (translate, mirror, scale, rotate)
- Wire EntityType::Underlay into all four match arms in traits.rs
- UNDERLAY command: FADE/CONTRAST/ON/OFF/CLIP ON|OFF/MONO ON|OFF
  subcommands to edit selected underlay entities
- Entity type name map entry for UNDERLAY

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 14:43:44 +03:00
Hakan SevenandClaude Sonnet 4.6 e38aa6b611 Feat: Solid entity (2D) — render, grips, properties, transform
TruckConvertible renders the 4 perimeter edges as wireframe outline.
The scene injects a solid-fill HatchModel for the filled quad using the
existing hatch GPU pipeline (DXF Z-order: p0→p1→p3→p2).
Grippable provides 4 square corner grips; grip moves rebuild the fill model.
PropertyEditable exposes all 4 corners and thickness. Transformable handles
move/rotate/scale/mirror via the standard entity transform path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 19:22:10 +03:00
Hakan SevenandClaude Sonnet 4.6 749f3b99dc Feat: hatch boundary grip editing — all edge types supported
Polyline, Line, CircularArc, EllipticArc, and Spline boundary edges
all get diamond grips at their control vertices. Dragging a grip updates
the underlying DXF boundary vertex and immediately rebuilds the GPU
hatch model via Scene::apply_grip.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 19:16:17 +03:00
Hakan SevenandClaude Sonnet 4.6 36d51286d4 Feat: dimension grip editing — all dimension types get stretch grips
Linear/Aligned: first point, second point, definition point, text position
Radius/Diameter: center (angle_vertex), radius point, text position
Angular2Ln/Angular3Pt: vertex, two extension points, arc def point, text
Ordinate: origin, feature location, leader endpoint, text position
Text position grip shared across all types; measurement recalculated after edit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 19:11:21 +03:00
Hakan SevenandClaude Sonnet 4.6 313e7226d2 Feat: Phase 5.4 — Table entity render (grid wireframe + cell text)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 23:11:09 +03:00
Hakan SevenandClaude Sonnet 4.6 7a5e3ed6ed Feat: Phase 6 — Face3D, PolygonMesh, PolyfaceMesh render; DRAWORDER command
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:13:37 +03:00
Hakan SevenandClaude Sonnet 4.6 dafa079b6a Feat: Phase 5 — MLine, Tolerance render; DimStyle Choice picker on dimensions
- mline.rs: MLine renders center spine + two parallel offset lines at
  ±scale/2 using the vertex miter directions; vertex grips; scale,
  closed and style-name properties
- tolerance.rs: Tolerance renders the GDT text string via font
  tessellation at insertion_point with rotation from direction vector;
  insertion grip and position properties
- properties.rs: Dimension entity's style_name EditText is upgraded to
  a Choice dropdown when document.dim_styles is non-empty, enabling
  point-and-click DimStyle assignment without a separate panel

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:06:20 +03:00
Hakan SevenandClaude Sonnet 4.6 27c0e74468 Feat: Phase 4.3/4.4/4.5 — RasterImage, Wipeout, AttributeDefinition, AttributeEntity
- raster_image.rs: RasterImage renders as border rectangle + X diagonals
  (pixel placeholder); Wipeout renders border or polygon clip boundary;
  both support insertion_point grip, brightness/contrast/fade properties,
  clipping toggle, and mirror transform (u/v vectors reflected)
- attribute.rs: AttributeDefinition renders default_value (or [TAG] if
  empty) as font-tessellated text; AttributeEntity renders the live value;
  both support insertion grip, position/height/rotation properties,
  and transform operations
- mod.rs + traits.rs: wire up all four new entity types through the full
  dispatch chain (to_truck, grips, geometry_properties, apply_geom_prop,
  apply_grip, apply_transform)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:00:15 +03:00
Hakan SevenandClaude Sonnet 4.6 4a93fc4949 Feat: Phase 4.1/4.2 — Polyline, Polyline2D, Polyline3D, Ray, XLine render and grips
- polyline.rs: TruckConvertible/Grippable/PropertyEditable/Transformable
  for all three polyline types; Polyline2D handles bulge arcs via the
  same truck Wire path as LwPolyline; Polyline and Polyline3D use
  TruckObject::Lines for straight-segment rendering
- ray.rs: Ray renders as base→+1e6; XLine renders as ±1e6; both have
  base-point and direction grips; mirror correctly reflects direction
  vector; base X/Y/Z and Dir X/Y/Z exposed in properties panel
- traits.rs: dispatch all five new entity types through
  to_truck_entity, grips, geometry_properties, apply_geom_prop,
  apply_grip, apply_transform

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 18:51:38 +03:00
Hakan Seven d2fdac7f1e first commit 2026-03-22 14:56:27 +03:00