Commit Graph
41 Commits
Author SHA1 Message Date
Hakan SevenandClaude Opus 5 2feac73eec fix(locale): put TCOUNT's new prompts back in the catalog
The placement options arrived with their prompts and messages written as
plain Rust strings, so they were the only command left speaking English
whatever the interface was set to.

They go through t! / tf! now like every other prompt, and the strings are
registered so the call actually reaches a translation: a source string
only resolves if the generated lookup knows it, and t! on an unknown
string just hands the source back. Keys follow what the table already
uses — the slug of the source, cut to forty-six characters, and the first
ten hex digits of its SHA-1 — which reproduces 2978 of the 3161 entries
exactly; the rest are hand-written ones predating the generator.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-08 03:19:54 +03:00
gianlucafiore b704a43872 Fix TCOUNT numbering and placement options 2026-08-07 19:50:11 -03:00
Hakan SevenandClaude Opus 5 5c5c7606a1 feat(select): offer the selection modes at "Select objects"
Only Previous and Last were on offer, so Window, Crossing, Fence, the two
polygons and All could not be reached at all -- and with no keyboard to
type them into, the buttons were the only way in.

Window and Crossing fix the sense of the next box. Dragging derives that
from the direction the corner travels and would overwrite it the moment
the corner moved, so the derivation stands down while a keyword holds it.
Add and Remove decide what a pick does for the rest of the round: Remove
subtracts the way Shift already does, rather than through PICKADD, which
decides whether a pick *replaces* the set and so would have wiped
everything gathered so far. Both are dropped when the next command
starts, since neither outlives the selection that asked for them.

Fence and the polygons are picked point by point, which TRIM and EXTEND
already ask for. That gesture -- the points, the rubber-banded dashed
preview, whether the path closes -- moves into one place both bind to,
and the two preview builders duplicated in trim.rs go with it.

A fence is not the polygon test with crossing set: that closes the point
list and counts whatever lies inside, so a line drawn past a row of
objects would take everything behind it too. It gets a hit test that only
counts a real intersection, and skips the area-based geometry entirely.

The lasso gathered its hits from wires, hatches, block hatches, meshes and
block meshes inline; the new modes need the same list, and a second copy
would drift. Both now come through `Scene::path_hit_handles`.

Closes #596

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-07 13:32:11 +03:00
Hakan Seven b92b8df997 fix(trim): handle lasso and box selection
Keep selection gestures in the active trim flow so crossed segments are modified instead of selected.\n\nRefs #487
2026-08-05 00:26:29 +03:00
Hakan Seven 657d023fb7 feat(ucs): integrate coordinate systems
Route coordinate input, geometry creation, transforms, properties,\nviews, and viewport persistence through a shared working plane.\n\nRefs #484
2026-08-04 23:17:54 +03:00
Hakan Seven 5662e07303 feat(area): support multi-object selection 2026-08-04 00:01:12 +03:00
Hakan Seven 48332ee807 feat(area): add object and aggregate modes
Mesh-backed measurements need cached surface metrics. Keep shared loop collection available in web builds.
2026-08-03 22:31:20 +03:00
Hakan Seven 3e6693b93f feat(locale): localize full interface 2026-08-02 22:09:25 +03:00
Hakan Seven e102887000 fix(move): hide source during preview
Refs #521
2026-08-02 16:32:47 +03:00
Hakan Seven dccaf95f49 feat(draw): continue paths on initial Enter
Start LINE, PLINE, ARC, and SPLINE from the latest path endpoint when Enter accepts the first point. Fall back to the active UCS origin.\n\nRefs #610
2026-08-01 19:09:19 +03:00
Hakan Seven 2c64888048 fix(blocks): preserve UCS transformations
Bake BEDIT frames into block-local geometry while keeping model and viewport UCS isolated. Normalize legacy nonzero block origins during load.
2026-07-30 19:50:33 +03:00
Hakan Seven a36e0d7fdc fix(matchprop): complete property matching 2026-07-28 19:53:39 +03:00
Hakan Seven 00cc17ea55 fix(scene): isolate drawing-space state
Cancel stale interaction state across space changes and keep live previews and zoom extents in their active paper/model context.\n\nRefs #539\nRefs #540\nRefs #541
2026-07-28 18:51:20 +03:00
Hakan Seven 05b044f367 perf(scene): make geometry edits incremental
Avoid full document, cache, and GPU rebuilds for entity deltas so add, delete, history, selection, and live polyline edits stay responsive on large drawings.
2026-07-28 17:16:27 +03:00
Hakan Seven b629dc32de feat(wipeout): add polygon creation modes
Closes #528
2026-07-27 21:50:50 +03:00
Hakan Seven b8889ccd20 feat(mview): add viewport creation options
Support polygonal and object viewports through native clip-boundary handles, including clipped rendering and selection.

Closes #525
2026-07-27 19:28:51 +03:00
Hakan Seven ecb29767d4 feat(offset): add multiple mode
Closes #477
2026-07-27 16:21:31 +03:00
Hakan SevenandClaude Fable 5 b32a9b4083 fix(plan): show options on activation instead of flipping the view (#326)
PLAN acted like a ViewCube TOP click the moment it ran — already on Top
meant an immediate flip to Bottom, and the options never appeared. It
now prompts "[Current ucs / Ucs / World] <Current>:" right on
activation and only changes the view once an option runs: Current =
plan of the active UCS, World = world XY, Ucs = prompts for a named UCS
(case-insensitive lookup). The new plan_snap goes straight to the plan
view with no flip-to-opposite cube behaviour.

KeywordCommand gains with_default(): a bare Enter at the verb step
dispatches the default verb (PLAN's <Current>) instead of cancelling.

Closes #326

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 16:53:32 +03:00
Hakan SevenandClaude Fable 5 9b28170d4b fix(undo): grip-drag history entry + mid-command Ctrl+Z steps (#332)
Grip drags mutated the document without ever pushing history — dragging
a polyline vertex (or any grip) could not be undone. The release-commit
now swaps the pre-drag backup in, snapshots that PRE state as a "GRIP"
entry, swaps the dragged result back and clears the redo stack; the
Esc-cancel path is unchanged and a no-move engaging click records
nothing.

Ctrl+Z during a drawing command steps the command instead of the
document undo swallowing the in-progress object (which also killed the
active command): new CadCommand::on_undo_step hook, consulted before
undo_active_tab. PLINE pops its last vertex (shared with the U option),
LINE reverts the last committed segment and keeps drawing from the
previous point (rides its existing U/UndoDocument path), and ARC
Continue reverts the last arc and resumes from the prior anchor with
the correct tangent via a new anchor history. With nothing placed yet
each falls through to the document undo.

Also drops the two warnings the #336 work left behind (unused Entity
import, dead Snapper::override_active).

Closes #332

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 15:48:22 +03:00
Hakan SevenandClaude Fable 5 9b40881ab1 feat(trim): TRIM/EXTEND options — edges, fence, crossing, edge, erase (#336)
Both commands gain a shared option mode machine:

- Cutting/Boundary edges (T/B): pick which objects act as the boundary
  (picked edges highlight yellow, the hovered candidate half-strength);
  Enter rebuilds the boundary set, empty = everything (quick mode).
- Fence (F): draw a dashed fence; every object crossing it is trimmed /
  extended at each crossing, re-applied to the surviving pieces so a
  fence across both overhanging ends clears both. Live red/cyan result
  preview while placing points.
- Crossing (C): crossing-selection semantics — the dashed green window
  picks objects crossing its edges AND wholly inside; runs through the
  fence machinery with a synthesized inside click.
- Edge (E): boundaries extrapolate (lines run past their ends, arcs
  close to full circles). Cuts that land on an implied extension draw a
  dashed yellow guide from the boundary's drawn end to the cut point,
  so the user sees which edge causes the cut. Extend previews also show
  the added tail as a bright dashed slice of the true curve.
- Erase (R, TRIM): picks delete without needing an intersection, with a
  red hover preview.
- Shift+click swaps trim<->extend per pick (new set_shift plumbing into
  the entity-pick and hover paths); the hover preview follows the held
  state. Project is out of scope for the 2D pipeline.

The per-type pick bodies moved to shared free fns (pick_trim_at /
pick_extend_at) used by direct picks, hover previews and the fence
pass; EXTEND's snapshot bookkeeping unified with TRIM's placeholder
flow. Option keywords now take precedence over the hex-handle reading
in feed_active_cmd ("F"/"C"/"E" are valid hex), and fence geos carry
sentinel handles — probing with NULL against NULL-handle geos excluded
the whole fence. Regression test: fence_trims_x_arm.

Closes #336

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 14:53:50 +03:00
Hakan SevenandClaude Fable 5 1870b8420f feat(pline): Undo option removes the last segment (#352)
U / UNDO (typed or via the prompt button) pops the last placed vertex
without ending the command, repeatably down to and past the start
point. The exit tangent of the remaining last segment is recomputed
from its bulge so a following Arc segment stays tangent-continuous.
New CmdResult::RemoveLiveEntity takes the live polyline out of the
document when Undo drops it below two vertices; the next point
re-creates it under the same undo unit.

Closes #352

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 11:17:01 +03:00
Hakan SevenandClaude Fable 5 e009d2d7a3 fix(rename): BLOCK type, stepped prompts, table re-keying
- RENAME gains the BLOCK type (stepped button + inline arm) via the
  shared Scene::rename_block.
- Stepped command front-ends (Rename, UserReg, Keyword, TwoValue,
  SelectThenTwoValue) returned None after consuming a typed token, and
  the driver treats None as "not consumed" — the same text was offered
  again and advanced two steps at once (RENAME dispatched old==new,
  SETVAR "X" became "SETVAR X X"). Consumed-but-prompting inputs now
  return NeedPoint.
- Symbol renames re-key the name-keyed Table (remove -> rename -> add)
  instead of mutating .name in place, which left the map keyed by the
  old name so later lookups silently failed. References (entity
  layer/linetype/style fields, layer linetypes, header current-* names,
  dim style refs on Dimension/Leader/Tolerance) are chased
  case-insensitively; layer 0/Defpoints and the built-in linetypes are
  protected; the undo snapshot is taken before the mutation so undo
  actually restores the old name.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 11:11:20 +03:00
Hakan SevenandClaude Fable 5 dc10c5dfba feat(edit): STRETCH crossing window selects objects implicitly (#338)
Bare STRETCH used to need a separate object-selection round before the
crossing window. Now the window itself picks the objects: with no prior
selection the command emits StretchWindow, the host gathers entities
whose world AABB touches the window (locked layers excluded) and
restarts at the base-point step. Over-selection is harmless since only
points inside the window move. The noun-verb flow (select first, then
STRETCH) is unchanged.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-21 22:35:35 +03:00
Hakan Seven e85e2aeb78 feat(commands): step POLYSOLID (select polyline, then width + height)
Add SelectThenTwoValueCommand (gather a selection, then two values) and use it
for POLYSOLID: bare POLYSOLID gathers the polyline if none is selected, prompts
for wall width then height, and dispatches POLYSOLID <width> <height>.
2026-07-16 14:47:45 +03:00
Hakan Seven 208e617868 feat(commands): step the selection-first text commands (bucket C)
Add SelectThenValueCommand (gather selection, then one value) and convert:
- SelectThenValueCommand: HYPERLINK (url), ARCTEXT (text), TEXTFIT (width),
  SCALETEXT (factor), TCOUNT (start), TEXTMASK (Enter to apply).
- SelectThenKeywordCommand: JUSTIFYTEXT (Left/Center/Right/Middle/Aligned/Fit),
  TCASE (Upper/Lower/Sentence/Title).

Each bare form gathers a selection when none is set, prompts, and delegates to
the inline handler. OBJECTSCALE already opens its dialog; TABLE CELL takes three
values (row/col/text) and stays typeable — TABLE bare already builds a table
interactively.
2026-07-16 14:37:10 +03:00
Hakan Seven 7195e1e8fb feat(commands): step the selection-first keyword commands
Add SelectThenKeywordCommand: if nothing is selected it first gathers a
selection (Enter confirms, following the ALIGN contract), then shows the
sub-verbs as buttons like KeywordCommand and dispatches `<name> <verb>
[value]` to the inline handler, which reads the still-selected set.

Convert CHPROP, ADJUST, XDATA, UNDERLAY and DRAWORDER. Verbs the single-value
generic can't express keep working by typing the full line: XDATA SET
<app> <value> and DRAWORDER Above/Under <handle> (a reference pick) are left
off the buttons; CHPROP/ADJUST/UNDERLAY are fully covered.

Verified end to end: SELECTALL then `CHPROP LAYER <name>` moves the selected
entity to that layer through the stepped front-end.
2026-07-16 13:55:49 +03:00
Hakan Seven 4c3509fa51 feat(commands): step the rest of the keyword/value commands
Convert the remaining bucket-B commands to prompt step by step instead of
requiring arguments or printing usage:

- KeywordCommand (buttons): VIEW, LINETYPE, SCALELISTEDIT, UCSICON, VSCURRENT.
- ValuePromptCommand (one value): LAYDEL (layer), ATTSYNC (block).
- TwoValuePromptCommand (new; two values): LAYMRG (source + target),
  SETVAR (variable + value, blank second reads).

Each bare form now starts the stepped front-end and delegates to the existing
inline handler; the argument form is kept and is the dispatch target. The
direct visual-style shortcuts (HIDDENLINE / XRAY / …) and UCSICON's argument
form are untouched.

COUNT is intentionally left alone: bare COUNT already reports the tally (a
useful inquiry action, not a usage line), so prompting would only add friction.
2026-07-16 13:29:04 +03:00
Hakan Seven 4fa6c49445 feat(commands): prompt ATTDISP and LAYERSTATE by keyword
Add KeywordCommand, a generic stepped front-end for keyword sub-verb
commands: bare NAME shows the sub-verbs as clickable buttons, and picking
one either dispatches `NAME <verb>` (action verbs like ATTDISP On/Off/Normal)
or prompts for an argument and dispatches `NAME <verb> <value>` (LAYERSTATE
Save/Restore/Delete <name>). It delegates to the existing inline handler, so
the logic stays in one place. First two of bucket B converted; the rest
(VIEW, LINETYPE, SCALELISTEDIT, SETVAR, LAYDEL/LAYMRG, and the selection-first
XDATA/UNDERLAY/ADJUST/DRAWORDER/CHPROP) can follow the same pattern.
2026-07-16 13:19:04 +03:00
Hakan Seven 1533c66a3e feat(userreg): prompt USERI/USERR for register then value
USERI/USERR set one of five integer/real header registers and needed both
inputs (register + value) typed on one line; bare printed usage. Add a
two-step front-end (UserRegCommand): it prompts for the register as 1–5
buttons, then the value, and dispatches USERI/USERR <n> <value> to the
existing inline handler. The argument arm now requires a space so the bare
name reaches the stepped command.
2026-07-16 13:14:37 +03:00
Hakan Seven 7cd5010729 feat(rename): prompt RENAME step by step instead of requiring all args
Bare RENAME printed a usage line and did nothing; only the fully-typed
`RENAME <type> <old> <new>` form worked. Add a stepped front-end
(RenameCommand) that prompts for the object type — as clickable buttons
(Layer, Text style, Dim style, Linetype, UCS, View) — then the current
name, then the new name, and dispatches to the existing inline handler.
The rename logic stays in one place; the argument form is kept and is also
the front-end's dispatch target. BLOCK is left off the buttons because the
inline handler does not implement it.
2026-07-16 12:51:34 +03:00
Hakan SevenandClaude Opus 4.8 62bd360e46 refactor(precision): widen command transform scalars and defaults to f64 (#311)
Completes the f64 migration on the CPU data path: the only f32 left now
is the GPU/render/screen layer, which is architecturally required (wgpu
vertex buffers and iced are f32; f64 vertices would double memory).

- EntityTransform::Rotate.angle_rad and Scale.factor are now f64 (the
  transform was already applied in f64 around the DVec3 center, so this
  only preserves the typed angle/factor). apply_standard_transform and
  apply_standard_scale take f64.
- CmdResult::ExtrudeEntity.height and AlignSelected.{angle_rad,scale}
  are f64; the EXTRUDE height parses as f64.
- defaults.rs (last-used construction values: circle radius/diameter,
  rotate angle, scale factor, offset/fillet/chamfer distance, array
  spacing/counts/angle) moved from Cell<f32> to Cell<f64>. Array counts
  round-trip through u32 (exact below 2^53).
- Consumers in circle/array/fillet/offset/rotate/scale/align/solid3d and
  dimension.rs rotate_point/scale_point follow. `as f32` is kept only
  where a value feeds a WireModel rubber-band/ghost (the preview path is
  screen-space f32).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-12 00:34:38 +03:00
Hakan SevenandClaude Opus 4.8 e015fbe328 fix(stretch): free crossing-window corners from Ortho, draw filled marquee (#291)
STRETCH picks its crossing window as two corner points. After the first
corner set last_point, Ortho/Polar constrained the opposite corner to an axis
through it, collapsing the window to a line and making selection impossible.

Add CadCommand::window_corner_pick(); STRETCH returns true for its two window
steps, and the viewport skips the ortho/polar (and OTRACK) lock for that point
in both the preview and commit paths — the corners are now free.

Also render the window like a normal box selection instead of a bare green
outline: add SelectionState::preview_box (a hit-test-free marquee), draw it
with the shared draw_marquee helper (green crossing fill + stroke), and drive
it from the command's new window_first_corner(). Cleared on command end.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-10 13:32:32 +03:00
Hakan SevenandClaude Opus 4.8 c45fe0267c feat(plot): QUICKPRINT/QP — plot a selection's bounding box to PDF (#325)
Run QUICKPRINT (or QP), select objects, then Enter: the selection's
bounding box becomes the plot window and a PDF is written next to the
drawing (<name>_<timestamp>.pdf) using the active page setup, with no
dialog. Model space.

Implemented as a selection-gathering CadCommand (src/modules/view/
quick_print.rs) returning CmdResult::QuickPrint(handles); the host
(on_quick_print_handles) unions the picked entities' AABBs, sets the
plot window, and reuses the tested clipped window-export path.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-09 12:57:35 +03:00
Hakan SevenandClaude Opus 4.8 c4fcfacb18 feat(draw): Arc Continue command; 3-Point default
Arc ribbon default + icon + dropdown order set to 3-Point. New ARC_CONT: tangent-continuing arc from the last line/arc endpoint, pick end only; Ctrl flips direction. Exit anchor recorded on commit (disambiguated by last pick) so chaining continues from the correct end.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-08 20:39:40 +03:00
Hakan SevenandClaude Opus 4.8 31ac5372d6 feat(command): clickable option buttons in the command line (#304)
Commands now expose their step options as clickable buttons rendered
inline beside the command-line prompt, so options need not be typed.

Adds a CmdOption/options() API to CadCommand: each command returns the
options for its current step; the command line renders them as
uppercase buttons and a click feeds the keyword to the command exactly
as if typed (an empty keyword submits like Enter).

Construction commands become "central" — CIRCLE offers [3P/2P/TTR/TTT/
DIAMETER], ELLIPSE [ARC/AXIS], ARC [SCE/SCA/SEA/SER/CSA/3P], RECTANGLE
[ROTATION/CENTER], POLYGON [CIRCUMSCRIBED/EDGE] — each keyword hands off
to the existing dedicated variant command via CmdResult::Dispatch,
instead of the variants only being reachable as isolated commands.

Migrates the existing bracketed-option prompts (PLINE, PEDIT, SPLINE,
SCALE, FILLET, CHAMFER, HATCH, GRADIENT, SOLID, POINT, RAY, XLINE, TRIM,
EXTEND) to the same button API and strips the option text from the
prompt strings, keeping value/coordinate hints. PEDIT's Width option
now enters a value sub-step so the button acts on click.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-08 00:16:59 +03:00
Hakan SevenandClaude Opus 4.8 9490c85b32 revert: drop PLOTWINDOW forced endpoint snap (#293)
Remove the forces_endpoint_snap mechanism merged in #293:
CadCommand::forces_endpoint_snap, Snapper::snap_forced_corners /
forced_corner_modes, the PlotWindowCommand override, the on_tick +
click-commit wiring, and the associated tests. PLOTWINDOW now uses the
normal snapper like every other command.

Rationale: forcing Endpoint snap on regardless of the global OSNAP master
overrides an explicit user setting and is surprising — a plot window is a
coarse print region that usually wants a margin, not a corner lock, and
the forced set only caught Endpoint (not center/mid/intersection) so it
was a partial, opinionated helper. Parking it pending a design discussion
with the PR author; can be reinstated behind a clearer UX (e.g. respecting
OSNAP, or an opt-in modifier) if justified.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-06 20:35:50 +03:00
sLuCHa 6cd422e5b9 feat(plot): snap plot-window corners to geometry endpoints
PLOTWINDOW / PW now forces Endpoint object-snap while picking its two
corners, independent of the global OSNAP toggle, so the plot area lands
exactly on frame corners. The snapper's master toggle and configured
modes are saved and restored around the pick, so the user's OSNAP
settings are unchanged afterward.

- CadCommand::forces_endpoint_snap() opt-in (default false; PlotWindowCommand true).
- Snapper::snap_forced_corners() forces Endpoint only, then restores state.
  Intersection is deliberately excluded: it is O(n^2) over the hit-test wire
  set and froze the UI on large drawings when a plot window is picked
  zoomed-out. Frame corners are endpoints, so Endpoint alone suffices.
- the cursor-move handler routes the plot-window pick through the forced path.

Works in model and paper space (shared pick path). Tests: opt-in flag;
forced mode set is endpoint-only; snapper state is restored after the call.
2026-07-06 13:38:56 +02:00
Hakan SevenandClaude Opus 4.8 e366e47b05 feat(draw): LINE deferred tangent — a line tangent to two circles
A line whose FIRST point is a Tangent snap on a circle can't be fixed
until its direction is known, and a line tangent to TWO circles is their
common tangent — neither is resolvable at a single pick. A plain LINE
dropped the tangent object, so it drew a wrong line (TAN-TAN between two
circles).

Add an opt-in on_point_with_tangent hook (default ignores the tangent, so
every other command is byte-for-byte unchanged) and route the running
Tangent object through the point commit. LINE defers a first-point circle
tangent and resolves it on the next pick: against a second circle tangent
it picks the common tangent of the two circles (up to four — chosen by
the two cursor hits, so hovering selects inner/outer + side); against a
plain point it draws the tangent from that point to the circle.
last_point syncs to the resolved anchor. Common-tangent and point-tangent
math is f64 with perpendicularity unit tests.

Refs #274

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-05 13:06:36 +03:00
Hakan SevenandClaude Opus 4.8 ab0a4f790c fix(insert): place block attributes by their ATTDEF geometry, follow the block (#255)
Inserting a block piled every attribute at the origin: each AttributeEntity
was built from just tag + value with default geometry. Carry the full
AttributeDefinition through the attreq flow and build attributes with
AttributeEntity::from_definition, then apply the block's insertion transform
so each lands in WCS at its proper position / alignment / rotation.

Attributes are stored in world space, so moving the block must move them
too. The MOVE command already did (acadrust translate_insert); apply_grip
(grip-drag) and the Position X/Y/Z property edit now translate the
attributes by the same world delta so they no longer stay behind.

Rotate/scale/mirror of a block still don't carry the attributes — acadrust's
transform_insert has no attribute pass — tracked separately.

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

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

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

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-01 08:05:25 +03:00
Hakan SevenandClaude Opus 4.8 bbdbd0850b chore: remove dead extend stub, flatten single-file module dirs
- Delete src/modules/draw/modify/extend.rs (a 1-line placeholder with no
  tool()/logic; `extend::` was referenced nowhere) and its `mod extend;`.
- Flatten single-file module dirs to the modern flat style:
  src/command/mod.rs -> src/command.rs, src/snap/mod.rs -> src/snap.rs.
  Parent `mod command;`/`mod snap;` are unchanged.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-26 23:00:26 +03:00