Commit graph

813 commits

Author SHA1 Message Date
Hakan Seven
40a52cea79 fix(dynamic-input): offset the prompt/boxes off the crosshair evenly
The row layout sat flush against the cursor's horizontal axis. Place the
prompt one gap (the same as the horizontal offset) below the axis and the
value boxes a further gap below the prompt, so the block clears the
crosshair symmetrically.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 22:23:35 +03:00
Hakan Seven
9b07edb1b4 assets: update ellipse arc icon
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 22:04:07 +03:00
Hakan Seven
5128d94b2b feat(dynamic-input): ARC specs + ellipse-arc preview fixes
- ARC: per-step DynSpec for the typed-value modes — included-angle (SCA,
  CSA), chord length (SCL, CSL) and radius (SER) show their box and route
  the typed value through on_text_input via a new dyn_commit_as_text()
  hook; the angle box previews the live span. Point/3P/SCE steps stay on
  the legacy polar path.
- ARC + ellipse-arc: derive the previewed sweep direction from the swept
  angle with a ~10° tolerance and advance the reference only on a clear
  move, so small cursor jitter no longer flips the arc. Ellipse uses the
  parametric angle so a flat ellipse isn't sticky.
- Ellipse arc: the start-angle step now shows a line from the centre to
  the cursor (it only picks the start angle) instead of a misleading arc.
- Ellipse arc: use the same minor-axis direction (Z x major) as the
  rendered entity so the committed arc matches the preview instead of
  mirroring across the major axis.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 22:03:04 +03:00
Hakan Seven
e31dbcb5c4 feat(dynamic-input): per-step specs for rectangle, polygon and ellipse
Extend the DynSpec coverage and add the guides those commands need:

- Rectangle: two-corner enters width/height as unsigned magnitudes (the
  sign follows the cursor side, like the angle entry), drawn with the
  rectangle as the guide; rotated rectangle's height is a single distance
  measured square to the base edge (dimension line offset off the edge
  with extension lines); centre rectangle shows half-width/half-height.
- Polygon: inscribed/circumscribed vertex step shows radius + rotation.
- Ellipse: minor-axis step (all three modes) measures the half-length
  perpendicular to the major axis and draws that semi-axis from the
  centre; angle steps anchor their arc at the centre.

Adds DynGuide::Perp / PerpDim (perpendicular measure to a reference line)
and DynSpec::ref_point, plus Width/Height role handling (unsigned display,
cursor-signed commit) and diameter value scaling.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 18:46:34 +03:00
Hakan Seven
b0ee1c39bd feat(dynamic-input): per-step DynSpec framework + guide overhaul
Introduce a per-command, per-step dynamic-input description so each step
shows the value boxes and guide geometry that make sense for it, instead
of a one-size-fits-all distance/angle pair.

- command: add DynSpec{anchor, fields(role+label), guide}, DynRole
  (X/Y/Z/Distance/Angle/Radius/Diameter/Width/Height/Factor/Count with
  label + value scaling), DynGuide(None/Polar/AxisDelta/Radius/RectSides)
  and DynAnchor. New dyn_spec() trait method defaults to None so commands
  on the legacy dyn_field() path are unchanged.
- overlay: redraw the dynamic-input layer by guide — polar reference line
  + angle arc, single radius line, dotted axis legs, or a cursor row —
  and place each box by its role. Angle reads as the unsigned magnitude
  of the short arc; a typed polar angle takes the sign of the cursor side.
- app: route fields/guide/anchor through the tab; resolve points from the
  step anchor and de-scale typed values by role (typed diameter -> radius).
- circle: CR shows a radius value on one line to the cursor; CD shows the
  diameter (twice the cursor radius). No angle arc on radius steps.
- pline/mline: keep polar dynamic input on vertex steps that also accept
  keyword letters via point_step_accepts_keywords().

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 17:12:08 +03:00
Hakan Seven
18f1688486 Revert "fix(input): honor @ / # coordinate prefixes during dynamic input"
This reverts commit df616482e2.
2026-06-15 13:46:27 +03:00
Hakan Seven
df616482e2 fix(input): honor @ / # coordinate prefixes during dynamic input
While DYN fields were showing, a leading @ or # landed in the command
line but the following digits were captured by the focused DYN field,
splitting the value so the prefix never resolved. Treat a leading @ / #
as an escape: route the whole coordinate (digits and separators) to the
command line so the relative (@) / absolute (#) prefix works the same
whether DYN is on or off.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 13:31:25 +03:00
Hakan Seven
fbac39462e fix(input): command line coordinates are always absolute
A bare command-line coordinate followed the DYN setting, so with dynamic
input on it was treated as relative to the last point. AutoCAD keeps the
command line absolute regardless of DYN; only the DYN tooltip defaults to
relative. Resolve a bare command-line value as absolute and reserve
relative for the explicit `@` prefix (`#` still forces absolute). The DYN
tooltip path keeps its own relative-by-default behaviour.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 13:27:30 +03:00
Hakan Seven
540d5f7b78 fix(xclip): clip hatch fills and render nested-block hatches
Hatch fills render through the separate HatchModel pipeline, so the
block wire clip never touched them: hatches outside an XCLIP boundary
were still drawn. Clip each hatch boundary loop to the clip polygon
(Sutherland-Hodgman, even-odd islands preserved) when the insert carries
a spatial filter.

Also fix hatches inside the boundary that were never drawn: the hatch
collector exploded each insert only one level, so hatches nested in
sub-blocks were dropped entirely. Walk the full block tree (depth
guarded) so nested hatches render and clip like the rest.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 13:02:55 +03:00
Hakan Seven
dd1ec3ad40 feat(xclip): clip block references to their SPATIAL_FILTER boundary
Block references carrying an XCLIP spatial filter were drawn in full,
ignoring the clip boundary. Resolve the filter through the INSERT's
extension dictionary (ACAD_FILTER -> SPATIAL) and clip the expanded
block geometry to the boundary polygon: polylines are split into the
inside runs, fill triangles are clipped, and snap/key vertices outside
the boundary are dropped.

The boundary vertices live in the clip-definition space, so they are
placed with world = T_insert * (inverse_block_transform * vert); this
keeps the clip correct even when the insert was rescaled after the clip
was created. Bumps acadrust to the build that decodes SPATIAL_FILTER.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 12:29:10 +03:00
Hakan Seven
ec865a95aa feat(plugin): add a Plugin Manager window listing installed add-ons
Read-only inventory of the add-ons compiled into the build — name, version,
id, API level, description, command prefixes — built from the extracted
`ocs_plugin_api` manifest. Opened with the `PLUGINS` / `PLUGINMANAGER` command
or the Start-page "Plugins" button.

Adds `installed_manifests()` to the plugin registry and wires the window the
same way as the existing About / Shortcuts windows.

Part of #100 (phase-1 plugin manager UI stub).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 01:46:09 +03:00
Hakan Seven
72ec1146df refactor(plugin): extract ocs_plugin_api crate for the stable add-on contract
Move the dependency-free, semver-versioned half of the plugin contract into a
standalone workspace crate `crates/ocs_plugin_api`:

- manifest types: PluginManifest, ApiVersion, API_VERSION
- ribbon vocabulary: CadModule trait + ToolDef/RibbonGroup/RibbonItem/IconKind/
  ModuleEvent/StyleKey

The host re-exports them from `crate::plugin::manifest` and `crate::modules`, so
every existing call site is unchanged. The acadrust-typed runtime surface
(HostSession) stays in the host binary; lifting it behind a HostApi trait in the
same crate is the remaining phase-1b step.

Part of #100. Docs updated in docs/plugin-architecture.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 01:36:04 +03:00
Hakan Seven
7a4ddbc62e chore(release): bump to 0.5.6
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 01:33:55 +03:00
Hakan Seven
3522637f65 fix(start): enable Send Feedback / Release Notes on the start tab
The start (welcome) tab blocks any command that isn't NEW/OPEN/EXIT/QUIT,
so the Contribute and Release Notes buttons did nothing but print
"No drawing open". REPORT and CHANGELOG (and ABOUT) only open a URL or a
dialog and need no drawing, so allow them through.

Also rename the "Contribute" button to "Send Feedback" (#44) and update
the REPORT status line to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 01:12:29 +03:00
Hakan Seven
036ac7dd86 fix(command): submit typed command on Enter without focusing the input (#99)
Unfocused keyboard input routes through the global subscription: typed
characters reach the command line, but Enter went to CommandFinalize, which
only forwarded the buffer to CommandSubmit while a command was already active.
At startup (before the window grabs focus) typing a command name and pressing
Enter did nothing until the user clicked into the command line. Forward any
non-empty buffer to CommandSubmit regardless of active-command state.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:35:03 +03:00
Hakan Seven
0badf48454 feat(scene): tessellate loaded ACIS solids via the truck B-rep kernel
Rebuild every ACIS face as a truck topological Face and mesh it with truck,
routing loaded 3DSOLID/BODY/REGION/SURFACE through the same kernel the Model
tab uses. plane→try_attach_plane, cone/cylinder/sphere/torus→revolution faces
(truck's Surface has no cone/sphere/torus), spline→BSplineSurface grid sample.
Per-vertex normals are computed analytically outward per surface type and
triangle winding is oriented to match, since truck's own orientation isn't
consistent across independently built faces. `tessellate_solid3d|body|region|
surface` try this first and fall back to the bespoke sampler.

Light the mesh shader with three spread directional lights plus ambient
(abs(dot) per light, two-sided) so faces — including the inner walls of an
open lofted surface — never read as a flat dark mass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:30:18 +03:00
Hakan Seven
9d823363f1 feat(scene): render 3D surface entities (loft/sweep/extrude/etc.)
ACAD_SURFACE entities now load and render. Their NURBS faces are
tessellated by building a truck BSplineSurface from the ACIS `spline-surface`
control net and knot vectors, then sampling its parametric grid — reusing the
same NURBS kernel the Model tab already builds on. Analytic faces
(plane/cone/sphere/torus) continue through the existing tessellator.

- New spline_tess.rs: parse the ACIS `nubs` block (degrees, knots with the
  clamped end-multiplicity fix, control grid) into a truck BSplineSurface and
  mesh it.
- tessellate_surface + Surface wired through the mesh-build, fallback-wire,
  and entity-classification paths.
- Bump acadrust to the commit that adds the Surface entity.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 20:11:44 +03:00
Hakan Seven
b173f32d5a fix(scene): tessellate cone and cylinder 3D solids
Cone and cylinder bodies rendered empty because their geometry depends on
circular edges the previous boundary walk couldn't use:

- Sample ellipse/circle boundary edges into multiple points so circular caps
  build a real polygon instead of a single degenerate vertex.
- Recover a cone/cylinder lateral face's height span from the solid's coaxial
  circle rims (plus a true cone's analytic apex) when the face boundary
  collapses to one height.
- Wind cone-side quads and plane-face fans so their face normals point
  outward, keeping flat-shaded and Gouraud lighting consistent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 15:43:24 +03:00
Hakan Seven
a2cb833c83 fix(scene): render raster images at correct position and size (#98)
Match the image shader's uniform layout to the shared 112-byte Uniforms
struct (was 144) and project quad corners via view_proj so texture-quad
draws no longer fail uniform binding validation.

Offset image quad corners by world_offset, matching all other Model-space
geometry, so rasters land in the same local space instead of being shifted
away. Downscale oversized images to the GPU's max texture dimension (8192)
to keep texture creation from failing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 15:06:06 +03:00
Hakan Seven
a819a47c08 fix(image): resolve raster image paths so DWG-embedded images render (#98)
A RasterImage stores its path on the linked ImageDefinition, usually as the
original author's absolute path (e.g. a Windows/VMware share) that doesn't
exist locally, so the image silently failed to load. On open, resolve each
raster image: use the stored path if it exists, else fall back to the same
file name next to the drawing, and write the resolved path onto the entity.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 14:38:54 +03:00
Hakan Seven
b7c5103891 feat(ui): show RGB for unnamed palette colours instead of "Index"
Picking a colour from the full palette showed a generic "Index" label.
Add color_display_name: standard names for ACI 1-9 / ByLayer / ByBlock,
"R,G,B" (0-255) for every other indexed or true colour. Used by the shared
colour selector button and the ribbon colour combo.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 14:27:35 +03:00
Hakan Seven
f7734b698f feat(ui): use the shared colour selector in properties, ribbon and layers
Replace the bespoke colour pickers with the shared color_selector / color_list
widget so colour selection is identical everywhere:
- left properties panel (selected entities' colour)
- ribbon Home-tab colour dropdown
- layer manager per-layer colour

Each routes its "More…" entry to the standalone Select Color window via a
ColorPickTarget (Properties / Ribbon / Layer). Extracted color_list as the
shared popup content; the colour selector button now fills its container.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 14:22:24 +03:00
Hakan Seven
dfb2c6f9d7 chore(release): bump to 0.5.5
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 11:20:18 +03:00
Hakan Seven
3d050fe1ab feat(ui): move full ACI palette to a separate "Select Color" window (#94)
The colour selector popup now lists only the named colours (ByLayer,
ByBlock, ACI 1-9) plus a "More…" entry. "More…" opens a standalone
"Select Color" window with the full 256-colour grid; picking there applies
to the originating field (dimension/multileader/table style) and closes
the window. Routed via a ColorPickTarget so one window serves every field.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 11:14:14 +03:00
Hakan Seven
3a87a18f32 fix(ui): float the colour-selector popup instead of pushing the form (#94)
The colour list/palette was laid out inline, shifting everything below it
down when opened. Wrap it in a small custom widget (Floating) that renders
the button inline and the popup as an iced overlay anchored below it, so it
floats over the UI like a real dropdown. Picking a colour now also closes
the popup (the style editors clear their open-field state on edit).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 11:00:43 +03:00
Hakan Seven
96a5a32735 feat(ui): show colour swatches beside names in the colour selector (#94)
Reworked the shared colour selector from a plain text pick_list into a
dropdown button that opens a list where each named colour (ByLayer,
ByBlock, ACI 1-9) shows its swatch next to the name, with the full ACI
palette grid below. The dimension/multileader/table style editors pick
it up unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 10:47:20 +03:00
Hakan Seven
8cdb17a6b4 feat(ui): shared colour selector used across all style editors (#94)
Add a reusable color_selector widget (ui/color_select.rs): a main-colour
dropdown plus a "more colours" button that expands the full 255-entry ACI
palette — the same design the properties panel uses. Replace the flat ACI
swatch rows added earlier in the dimension, multileader and table style
editors with it, wired through each editor's existing colour edit message
(the chosen colour is encoded as an ACI string) plus a per-field
palette-open toggle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 10:42:39 +03:00
Hakan Seven
3ccda2f129 feat(style): pick colours from ACI swatches in the style editors (#94)
Dimension, multileader and table style editors took colours as raw ACI
integers in a text box. Replace those with a swatch row (the 9 standard
ACI colours + ByLayer) that highlights the current value, reusing each
editor's existing colour edit message (the chosen index is sent as the
field's string value, so no new plumbing).

Text styles carry no colour field, so none was needed there.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 10:15:14 +03:00
Hakan Seven
e263cb2458 fix(dimension): break the dim line behind on-line text so DIMTFILL reads (#94)
2-D fills (the DIMTFILL background) render in a pass before all wires, so
the background could never sit above the dimension line — the line showed
through it. When the text sits on the line, gap the dimension line across
the text box (AutoCAD-style break) so the background reads cleanly over
the line. Text placed above/below the line is unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 10:09:28 +03:00
Hakan Seven
5f6c4029e9 fix(mleader): new multileader inherits the current MLeader style (#94)
A new multileader was built from defaults and ignored the current
MLeaderStyle, so the style editor's settings had no effect on it (the
renderer reads the entity's own fields, not the style). commit_entity_handle
now copies the style's content/path type, text attachment/alignment/angle,
colours, sizes, scale and landing into the new entity (enum types
round-trip through i16 since the entity and style enums are distinct).

Text styles already render correctly and tables already resolve their
style live via table_style_handle, so no change was needed there.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 09:59:12 +03:00
Hakan Seven
6aa47c6ead fix(dimension): DIMZIN feet/inch suppression and DIMJUST 3/4 rotation (#94)
- DIMZIN now drives architectural feet/inch zero-suppression (modes 0-3)
  inside format_architectural, threaded through format_with_unit (primary
  and alternate units).
- DIMJUST 3 and 4 (over first / second extension) now rotate the text 90°
  to read along the extension line, not just shift its position.
- DIMTAD 2 (outside) and 3 (JIS) resolve to the away-from-object side,
  which equals "above" for 2-D linear dims; clarified in a comment.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 09:42:11 +03:00
Hakan Seven
edacc895f7 fix(dimension): honour DIMTAD below and DIMTFILL background fill (#94)
Two style settings were accepted by the editor but ignored by the
renderer:
- DIMTAD=4 (Below) placed text above the dimension line like DIMTAD=1;
  the text is now offset to the opposite side.
- DIMTFILL=1 (drawing background) drew no fill; it now masks the geometry
  behind the text with the background colour (DIMTFILL=2 already used
  DIMTFILLCLR).

Verified the other enum settings render: DIMLUNIT/DIMFRAC unit formats,
DIMAUNIT/DIMADEC/DIMAZIN angular formats, DIMJUST positions,
DIMATFIT/DIMTMOVE fit, DIMTOLJ tolerance alignment, and the alternate-unit
/ zero-suppression families.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 09:37:01 +03:00
Hakan Seven
f93bda1800 feat(dimstyle): use named dropdowns for enum style settings (#94)
The dimension style editor exposed every enum setting (DIMTAD, DIMJUST,
DIMLUNIT, DIMTMOVE, DIMATFIT, DIMTFILL, DIMFRAC, DIMAUNIT, DIMAZIN,
DIMALTU, DIMTOLJ, DIMARCSYM, and the zero-suppression family) as a raw
integer text box, forcing the user to type codes like "1". Replace them
with named pick_list dropdowns via an enum_field helper that maps the
stored code to a label and back. Numeric fields (sizes, colours,
decimals) and obsolete flags (DIMUNIT/DIMFIT) keep their text inputs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 09:28:36 +03:00
Hakan Seven
b211ca07a9 feat(dimension): flip arrowheads outside when they don't fit (#94)
When the dimension line is too short for the arrowheads, they are now
placed outside the extension lines (tip on the line, body outward) with a
short stub to sit on, instead of overlapping inside. DIMSOXD suppresses
those outer stubs. Ticks are unaffected (they always fit).

DIMATFIT's exact mode ordering and DIMUPT remain for a later pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 02:13:00 +03:00
Hakan Seven
40a91372fd feat(dimension): honour DIMTIX/DIMATFIT text fit; clarify remaining flags (#94)
Centred dimension text that doesn't fit between the extension lines now
slides outside (text-outside placement), unless DIMTIX forces it to stay
inside. DIMTOFL is already satisfied for linear/aligned dims (their dim
line is always drawn between the extension points).

The remaining style flags are documented in place:
- DIMATFIT arrow-outside modes and DIMUPT need an arrow autofit pass.
- DIMTXTDIRECTION (RTL) needs single-line text direction support.
- DIMARCSYM / DIMJOGANG apply only to arc-length / jogged-radius dims,
  which aren't shipped as entity variants.
- DIMUNIT is obsolete (superseded by DIMLUNIT).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 02:03:05 +03:00
Hakan Seven
006dbe4631 fix(dimension): make DIMTAD/DIMTVP/DIMJUST drive text placement (#94)
Dimension text position ignored the style: the renderer returned the
saved text_middle_point whenever it was non-zero, which it always is for
app-created dims, so DIMTAD ("text over the dimension line" / ISO) and
friends had no effect — text could only be moved by grips.

Use the new acadrust text_user_positioned flag: when the text wasn't
user-placed, compute the position from the style (DIMTAD/DIMTVP/DIMJUST)
anchored on the dimension line (definition_point); when it was (grip drag
or properties edit, both now set the flag), keep the saved point.
Imported drawings keep their fidelity via the flag round-tripping through
DXF/DWG.

Also fixes linear/aligned text anchoring at the measured midpoint instead
of the actual dimension line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 01:57:58 +03:00
Hakan Seven
68a3efa83d fix(style): new mleader/table use the current style (#92)
Follow-up to the text/dimension fix: MultiLeader and Table were created
at their default style too. Their styles live in the objects dictionary,
so commit_entity_handle now resolves header.current_mleader_style_name /
current_table_style_name to the matching style object's handle and
assigns it, unless the command already set one or no such style exists.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 01:19:00 +03:00
Hakan Seven
92e32243eb fix(style): new text/mtext/dimension use the current style (#92)
New annotation entities were created at the entity "Standard" default
instead of the document's current style, so making a style current had
no effect on creation.

- Text / MText: seed the new entity (and the MText editor preview) from
  header.current_text_style_name.
- Dimension: commit_entity_handle fills the new dimension's style_name
  from header.current_dimstyle_name, covering every dimension command
  centrally.

Applied only when the entity is still at its default so an explicitly
styled entity is preserved. MLeader and Table styles need their style
tables modelled first and are left for follow-up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 01:15:52 +03:00
Hakan Seven
29ccfcfc46 fix(command): accept typed points/Enter in keyword steps when DYN is off (#97)
A command step that takes both a point and option keywords (PLINE,
MLINE) returns true from wants_text_input to receive the keywords, but
CommandSubmit then routed the text only to on_text_input and, on a None
(unhandled) result, re-prompted instead of falling through. So with
dynamic input off, typed coordinates and a bare Enter were swallowed —
points couldn't be added by keyboard and the command couldn't be ended.

Fall through to the existing Enter / coordinate handling when
on_text_input doesn't consume the text. Coordinates (including @ and #
prefixes) and Enter now work in these steps with DYN both on and off;
commands that fully handle their text step still return Some and are
unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 00:59:52 +03:00
Hakan Seven
e141fb6df3 fix(command): block drawing commands on the Start tab (#96)
The Start (welcome) tab has no drawing, so commands like LINE dispatched
from the command line or ribbon ran as silent no-ops. Allow only the
commands that make sense there (NEW / OPEN / EXIT / QUIT; OPEN_RECENT is
handled earlier) and inform the user otherwise.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 00:42:02 +03:00
Hakan Seven
bc92590725 fix(stretch): re-tessellate stretched entities so the viewport updates (#95)
STRETCH edited geometry directly via document.get_entity_mut, which the
scene's tessellation cache doesn't observe, so the viewport kept showing
the pre-stretch shape until an unrelated redraw. Mark each stretched
entity dirty and bump geometry on completion, matching MOVE's
transform_entities path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 00:36:17 +03:00
Hakan Seven
8d6e21ef5f fix(layers): sync header CLAYER when making a layer current (#93)
Making a layer current via the layer manager (LayerSetCurrent) or
LAYMCUR updated only the per-tab active_layer, not the document
header's current_layer_name/handle. The no-selection ribbon refresh
reads the header layer, so after the change an Esc (deselect ->
refresh_properties) snapped the active-layer dropdown back to the
stale header value ("0") even though new entities still used the
correct active layer. Mirror the change into the header in both paths,
matching the ribbon dropdown's own set-current path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 00:16:06 +03:00
Hakan Seven
5848569368 fix(fillet): correct wrap-around corner on closed polyline (#91)
The last corner of a closed polyline joins its first (0) and last (n-1)
segments at vertex 0, but the corner fillet/chamfer used corner_idx
high%n (= n-1) and treated seg low as the "before" segment, so the
shared vertex and the before/after order were both wrong — producing a
fillet/chamfer at the wrong place. Detect the wrap pair and map
before_seg=n-1, after_seg=0, corner_idx=0. Applies to FILLET and
CHAMFER.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 00:10:39 +03:00
Hakan Seven
ae86ad7582 fix(trim): assign handle to trimmed polyline so it can be trimmed again (#65)
TrimCommand::on_entity_replaced never matched LwPolyline, so a trimmed
(closed or open) polyline kept a NULL handle in the command's entity
snapshot. A second pick on the same polyline then found nothing, so it
could not be trimmed more than once without restarting the command.
ExtendCommand already handled this case.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 00:04:38 +03:00
Hakan Seven
57d3e620ea fix(command): keyword/radius input for ribbon-started modify commands (#90)
Starting FILLET/CHAMFER from the ribbon left the command-line field
unfocused, so its Enter arrived as CommandFinalize and discarded a
typed option keyword ("R"/"D"), cancelling the command. Several
related dynamic-input issues surfaced from the same flow:

- CommandFinalize now forwards a non-empty command-line buffer through
  CommandSubmit, so a typed keyword is handled the same whether the
  command was started from the ribbon or the command line.
- sync_dyn_fields shows no coordinate box during an object-pick step
  (needs_entity_pick / needs_structure_point_pick) — there is no point
  to enter there, so typed keywords reach the command line cleanly.
- apply_cmd_result rebuilds the dynamic-input fields on NeedPoint, so a
  step change (object pick -> radius entry) shows the matching box
  immediately and typed digits land in it instead of the command line.
- Object-pick steps now draw a prompt-only hint pill at the cursor
  (no input box).
- FILLET/CHAMFER remember the first pick across a mid-selection radius
  or distance entry, resuming the second pick instead of restarting
  selection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 23:58:56 +03:00
Hakan Seven
3bafe45ab3 fix(wix): show GPL-3 license on installer EULA page
WixUI_Minimal fell back to WiX's built-in placeholder (Lorem ipsum)
RTF because no WixUILicenseRtf was set. Ship License.rtf generated
from the repo GPL-3 LICENSE and point the variable at it via a new
-dLicense candle arg.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 16:55:09 +03:00
Hakan Seven
4a1a658d07 fix(wix): write default registry values without empty Name (CNDL0006)
candle rejects RegistryValue/@Name='' — the DefaultIcon and
shell\open\command rows must write the key's default value by
omitting Name entirely. Empty Name broke the MSI build.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 15:33:08 +03:00
Claude
e87f331a1f
Revert "ci: allow workflow_dispatch to upload to an existing release tag"
This reverts commit 0bceb1e2a0.
2026-06-12 11:55:16 +00:00
Claude
0bceb1e2a0
ci: allow workflow_dispatch to upload to an existing release tag
Adds a release_tag input so the workflow can be manually triggered
to rebuild and upload artifacts to an already-published release
(e.g. after a hotfix on main without re-tagging).

https://claude.ai/code/session_01F7yMUY48VuGNUF1Q3ma2cZ
2026-06-12 11:54:17 +00:00
Hakan Seven
e26563ea5d
Merge pull request #89 from HakanSeven12/claude/release-action-windows-build-mm1lrn
fix(windows): cast COINIT_APARTMENTTHREADED to u32 for windows-sys 0.61.2
2026-06-12 14:48:20 +03:00