Commit Graph
86 Commits
Author SHA1 Message Date
Hakan SevenandClaude Opus 4.8 b3ba3a53d1 feat(styles): green ✓ for current style + resolve it from DWG files
- The current-style marker is now a green ✓ in its own fixed-width column
  so names stay aligned; rendered as a separate coloured glyph rather than
  baked into the label string.
- Resolve the current text / dimension / multiline style from the handle
  the DWG header stores into the name the app reads (fix_current_style_names
  on load). DXF already provides these as names ($TEXTSTYLE / $DIMSTYLE /
  $CMLSTYLE); DWG only stores handles, so the marker previously always fell
  back to "Standard". Only overrides when the handle resolves.

Note: table and multileader current styles are not surfaced by the file
reader (no header name/handle exposed), so those markers still default to
the app's active selection until acadrust exposes them.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-10 15:56:13 +03:00
Hakan SevenandClaude Opus 4.8 885bacd0f6 feat(styles): mark the current style with a ✓ in the list
Every style manager now shows a leading ✓ next to the current style
(current text/dim style, active table/multileader/multiline style), with
the other rows padded so names stay aligned. The marker replaces the
multileader/multiline-only ◀ and is wired for all five managers by
threading the current-style name into each view.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-10 15:45:48 +03:00
Hakan SevenandClaude Opus 4.8 de4eb31003 feat(styles): make style managers transactional — persist only on Apply
A style manager is now a staged transaction. When it opens, a snapshot of
the style tables, style objects and current-style pointers is taken. Every
New / Copy / Delete / Rename / Set Current / property edit mutates the
document live so the dialog previews the result, but the tab is not marked
dirty, nothing is pushed to undo, and the drawing is not rebuilt.

- Apply commits: one undo entry (restoring the pre-edit state), the tab is
  marked dirty, the drawing rebuilds, and the baseline is reset so further
  edits stage afresh.
- Closing the window without Apply discards: the opening snapshot is
  restored, so none of the changes persist.

Side effects (dirty / undo / bump_geometry) were removed from every style
edit handler and routed exclusively through the commit. Multiline's Apply
is a structural-only commit since its editor has no editable properties.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-10 15:38:32 +03:00
Hakan SevenandClaude Opus 4.8 65a25033bc fix(styles): make double-click inline rename actually fire
The list row wrapped a `button` inside the `mouse_area`. The button
captured the press, so the parent `mouse_area` never saw the second
click and `on_double_click` never fired — double-clicking a style name
did nothing.

Drop the inner button: the row is now a plain `mouse_area` carrying both
`on_press` (select) and `on_double_click` (start rename), with selection
shown via the container background. Focus the rename field on start so
the user can type immediately.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-10 15:10:09 +03:00
Hakan SevenandClaude Opus 4.8 f2dfd01795 feat(styles): unify the five style managers behind a shared frame
The text/dimension/table/multileader/multiline managers were hand-copied,
so their list CRUD kept drifting and breaking: Dimension's New created
nothing (#73), new text styles never reached the ribbon dropdown (#74),
and several were added with a NULL handle (dropped on DWG save, #67).

Collapse the duplicated parts into three shared pieces and leave only the
per-manager property editor bespoke:

- app/style_ops.rs: one StyleKind-dispatched CRUD layer (new / copy /
  delete / rename) handling handle allocation, ribbon sync, Table re-key
  and name-reference rewrites in a single place.
- ui/style_manager.rs: the window scaffold — uniform toolbar (New / Copy /
  Delete on the left, Set Current + Apply on the right), style list and
  chrome. Each manager now only builds its editor.
- ui/style_list.rs: the list row — single click selects, double click
  starts an inline rename.

New capabilities, now consistent across all five:
- Copy duplicates the selected style.
- Double-click a name to rename it inline.
- Right side is always Set Current + Apply (added Table set-current;
  MLine apply is a documented placeholder until its editor is editable).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-10 15:03:34 +03:00
Hakan Seven 6a70e99dd5 Merge pull request #80 from mf4633/feature/plugin-host
Add plugin host (Phase 1)
2026-06-10 00:37:37 +03:00
Michael Flynn 82993bc1db Add demo_plugin and plugin host integration tests
Minimal in-tree add-on (DP_HELLO) validates registry, ribbon merge, and try_dispatch. Five new lib tests; EntryKind gains PartialEq for test helpers.
2026-06-09 13:52:15 -04:00
Michael Flynn e46701456f Add plugin host architecture and Storm Sewer add-on package
Generic plugin runtime (src/plugin/, HostSession, per-tab plugin_state, command router). QGIS-style add-on layout with plugin.toml and single PluginRegistration. Storm Sewer refactored as reference consumer with dispatch.rs, catchments, LandXML, headless tests (43 passing). Core update.rs decoupled from storm_sewer via CadCommand object-pick hooks. Docs: plugin-architecture.md, plugin-template, PR and issue-78 reply drafts.
2026-06-09 13:41:21 -04:00
Hakan SevenandClaude Opus 4.8 ff10f8a89a feat(ui): elide overflowing text, tooltip full layer name
iced has no built-in ellipsis, so long user content (file names, layer
names, paths, property values) wrapped or spilled past fixed-width
panels. Add an `elide` helper (char-budget truncation with a trailing
ellipsis) and apply it to the layer manager, properties panel, document
tabs, recent-files list and the save dialog.

In the layer manager a truncated name reveals its full text in a
cursor-following tooltip on hover, so the column need not be widened.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-09 19:04:18 +03:00
Hakan SevenandClaude Opus 4.8 b3aadf569e fix(commandline): pin active step prompt instead of fading
The current step's prompt was written into the command-line widget
label. Instead, keep it as a normal history line but freeze its
cooldown: the step prompt is pinned so it does not fade while the user
is still on that step. When the step changes the previous line's
cooldown restarts; when the command ends the pin clears and it fades.

`update` is now a thin wrapper that mirrors the active command's prompt
into the command line after each message; the body moved to
`update_inner`.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-09 18:46:45 +03:00
Hakan SevenandClaude Opus 4.8 4b878b88c4 feat(input): scalar entry via dynamic input
Text-input steps (OFFSET distance, POLYGON sides, radii, counts) were
swallowed by the dynamic-input overlay: typed digits landed in the field
buffer and Enter committed a point pick, so the value never reached
on_text_input (issue #61). Now each text step shows one scalar box whose
value routes to on_text_input on commit; non-numeric prompts (names,
keywords) keep going to the command line so mixed text like "Bolt12"
isn't split.

OFFSET reworked: object first, then through-mode by default — the offset
follows the cursor at the perpendicular distance to the object. Typing a
number locks the magnitude (cursor then only picks the side); a value
typed and clicked without Enter is applied before the point pick.

The dynamic-input overlay and the command line now show the active
step's prompt and hold it until the step completes.

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

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

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-05 00:35:53 +03:00
Hakan SevenandClaude Opus 4.8 bb54cd034f fix(statusbar): cycling-list hover highlight on row re-entry
Row exit now clears the preview only when the highlight still points at
that row. Moving between rows can fire on_enter before the previous
row's on_exit, so the unconditional clear wiped a freshly highlighted
row (notably when returning to the first row). Guarding the clear fixes
the highlight not reappearing.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-05 00:05:15 +03:00
Hakan SevenandClaude Opus 4.8 a9228b9021 feat(statusbar): highlight cycling-list object on row hover
Add a scene hover_highlight handle that renders an entity with the
selection colour without joining the real selection. The cycling list
box sets it on row enter / clears on exit, so hovering a row glows the
matching object in the drawing.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-05 00:00:52 +03:00
Hakan SevenandClaude Opus 4.8 bcbda65746 feat(statusbar): selection cycling shows a pick list, adds to selection
Replace the repeat-click cycling with a list box: when a click lands on
two or more overlapping objects (cycling on), a small list of the
candidates opens at the cursor. Picking a row adds that object to the
current selection (accumulate); clicking outside dismisses it. A single
object under the cursor falls through to the normal click.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-04 23:56:24 +03:00
Hakan SevenandClaude Opus 4.8 ac042c5dbf feat(statusbar): selection cycling for overlapping objects (SC pill)
Add a click_hits_all hit-test and an SC pill that, when on, makes
repeated clicks at the same spot step through the overlapping objects
there (nearest first) instead of accumulating the selection. The whole
cycling path is gated behind the toggle, so default picking is unchanged
when it is off.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-04 23:44:39 +03:00
Hakan SevenandClaude Opus 4.8 f7eac09b55 feat(statusbar): selection filtering by object type (FILTER pill)
Add a per-type selection filter to the scene: the FILTER pill opens a
checklist of the entity types in the layout, and unchecking a type
excludes it from interactive picking (click, box and lasso selection all
honour it). The pill lights up while any type is filtered out.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-04 23:39:48 +03:00
Hakan SevenandClaude Opus 4.8 834780ec5d feat(statusbar): quick properties floating panel (QP pill)
When the QP pill is on, a compact floating panel appears at the canvas
top-left on selection, reusing the docked panel's editable section rows.
Toggleable from the status-bar customization menu.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-04 23:31:36 +03:00
Hakan SevenandClaude Opus 4.8 66f7d24bc9 feat(statusbar): transparency-display toggle (TPY pill)
Add a transparency_enable uniform read by the wire shader: when the new
TPY pill is off, every line is forced opaque; when on, baked entity
transparency shows through. Toggling is a uniform write, no retessellate
(same mechanism as the lineweight-display toggle). Pill is toggleable
from the status-bar customization menu.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-04 23:25:09 +03:00
Hakan SevenandClaude Opus 4.8 28ec360255 feat(statusbar): isolate action menu on the pill and right-click
Clicking the ISO pill now opens a small menu with Isolate Objects, Hide
Objects and End Isolation instead of ending isolation directly; rows
that don't apply (no selection / nothing hidden) are dimmed. The same
actions are added to the viewport right-click menu.

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

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-04 22:51:23 +03:00
Hakan SevenandClaude Opus 4.8 243a0bc923 feat(statusbar): drawing-units pill with INSUNITS picker
Add a Units pill that shows the drawing's current INSUNITS value and
opens a picker to change it (Unitless, mm, cm, m, km, in, ft, mi, yd).
Toggleable from the status-bar customization menu like the other pills.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-04 22:06:42 +03:00
Hakan SevenandClaude Opus 4.8 d829f80a04 feat(statusbar): customizable pills with coordinates and clean screen
Add a customization menu (far-right handle) that lists every status-bar
pill with a check mark; toggling a row shows or hides that pill, and the
choice persists across sessions in the config dir.

New pills:
- Coordinates: live cursor readout (re-adds the model-space world offset
  so it shows true drawing coordinates), updated on every move rather
  than only while a command is active.
- Clean Screen: hide the ribbon and side panels for a full canvas.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-04 19:14:04 +03:00
Hakan SevenandClaude Opus 4.8 edc8cbc969 feat(scale): drive scales from the drawing's scale list
Read the model-space annotation scale from the standard CANNOSCALE /
CANNOSCALEVALUE header variables instead of a user-variable hack, and
populate both the status-bar scale picker and the viewport Scale
property purely from the drawing's ACAD_SCALELIST — no built-in
fallback set. Xref-derived scales (`_XREF` suffix, `name|` prefix)
are filtered out so only the host drawing's own scales appear.

Bumps the patched acadrust to the commit that adds CANNOSCALE/
CANNOSCALEVALUE read/write.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-04 16:18:01 +03:00
Hakan SevenandClaude Opus 4.8 10d674f606 feat(tablestyle): complete field coverage (flow, description, cell data + borders)
Table Style editor now exposes every TableStyle / RowCellStyle field:
- General: description, flow direction (Down/Up dropdown).
- Per cell: data type, unit type, format string, plus all six borders
  (left/right/top/bottom/horizontal-inside/vertical-inside) with line
  type (Single/Double), line weight, color (ACI), double-line spacing
  and a visibility toggle.
Border type/visibility apply immediately; the numeric border fields and
data/unit/format are written by the existing "Apply cell" button.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-03 21:09:37 +03:00
Hakan SevenandClaude Opus 4.8 6ae24cceee feat(styles): complete MLeader field coverage + Dimension DIMUNIT
MLeader Style editor now exposes every MultiLeaderStyle field: line
weight, line type / arrowhead block / text style / block-content blocks
(handle dropdowns from the document's tables), the four text attachments
+ attachment direction, the full block-content group (color, connection,
rotation, X/Y/Z scale, enable scale/rotation), leader & multileader draw
order, align space, and description.

Dimension Style editor adds the last uncovered DIMUNIT field.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-03 21:04:22 +03:00
Hakan SevenandClaude Opus 4.8 578b8c5d64 fix(styles): keep style-editor scrollbar at the window's right edge
The detail-panel scrollables defaulted to shrink-to-content width, so
their vertical scrollbar landed in the middle of the panel next to the
content instead of at the window edge. Make the scrollables fill width
(and drop the dimstyle panel's right padding so the bar sits flush) in
the Dimension, Table and MLeader style editors.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-03 20:48:40 +03:00
Hakan SevenandClaude Opus 4.8 bd120ca307 refactor(styles): replace cycle buttons with dropdowns
The enum/handle pickers in the MLeader, Table and Dimension style
editors used "Cycle" buttons, which were awkward. Replace them with
pick_list dropdowns:
- MLeader: path type, content type, text angle, text alignment.
- Table per-cell: alignment (9 anchors).
- Dimension: arrowhead blocks (DIMBLK/1/2/LDRBLK) and ext-line linetypes
  (DIMLTYPE/LTEX1/LTEX2), options resolved from block_records/line_types.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-03 20:44:37 +03:00
Hakan SevenandClaude Opus 4.8 1b7edf6cae feat(dimstyle): block/linetype Handle cyclers for arrowheads & ext lines
The arrowhead-block (DIMBLK/DIMBLK1/DIMBLK2/DIMLDRBLK) and ext-line
linetype (DIMLTYPE/DIMLTEX1/DIMLTEX2) Handle fields are now editable in
the Dimension Style manager. Each shows the resolved block-record /
linetype name and a Cycle button that advances through the available
records (NULL = Default arrowhead / ByBlock linetype). Edits bump
geometry so dimensions re-render with the new arrowheads/linetypes.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-03 20:34:09 +03:00
Hakan SevenandClaude Opus 4.8 df44031ae8 feat(tablestyle): per-cell editing for Data/Header/Title rows
Each row's RowCellStyle is now editable in the Table Style manager:
text style name, text height, text & fill color (ACI), background-fill
toggle, and alignment (cycle through the 9 anchor positions). Margin and
per-cell buffers load on open/select via a shared load_tablestyle_bufs;
edits write through objects.values_mut() and bump geometry so tables
using the style re-render.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-03 20:28:58 +03:00
Hakan SevenandClaude Opus 4.8 e0c5db9e0c feat(mleaderstyle): add Multileader Style editor window
New dedicated style-manager window for MultiLeaderStyle objects (the
existing mlstyle window edits MLineStyle, not multileader). Opened via
the MLEADERSTYLE command / ribbon manager entry.

Editable across Leader Format / Structure / Content sections:
- path/content/text-angle/text-alignment enums (cycle buttons)
- line & text color (ACI), arrowhead & break-gap sizes
- landing distance/gap, max points, segment angles, scale factor
- default text, text height
- enable landing/dogleg, text frame, text-always-left, annotative
New/Delete/Set-Current style management.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-03 20:25:14 +03:00
Hakan SevenandClaude Opus 4.8 0dd86eb658 feat(tablestyle): editable General section (margins, flow-suppress toggles)
The Table Style editor's General fields are now editable: H/V cell margins
(buffers + Apply) and title/header row-suppressed toggles, loaded from the
selected style on select. Per-cell (Data/Header/Title) text/fill/border
editing remains a follow-up.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-03 20:13:30 +03:00
Hakan SevenandClaude Opus 4.8 a21caf821b feat(dimstyle): expand Dimension Style editor to the full field set
Adds the remaining ~40 DIMSTYLE variables across the tabs (and a new
Alternate Units tab): dim/ext line colors+lineweights, fixed-length ext
lines, separate arrow blocks, arc symbol, jog angle, text color/justify/
vertical pos/fill/direction, fit options (DIMATFIT/DIMTIX/DIMSOXD/DIMTMOVE/
DIMUPT/DIMTOFL/DIMFIT), decimal separator, rounding, zero suppression,
fraction + angular units, alternate units, and tolerance vert-just/zero
suppression. Only the arrowhead-block / extension-line-linetype Handle
references are left (they need a block/linetype picker).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-03 20:09:08 +03:00
Hakan SevenandClaude Opus 4.8 4675a439da feat(tablestyle): add Annotative toggle to the Table Style editor
The table-style details panel gains an Annotative checkbox that flips the
new TableStyle.annotative flag, rounding out annotative across the Text,
Dimension and Table style editors.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-03 17:51:45 +03:00
Hakan SevenandClaude Opus 4.8 07a2a05975 feat(dimstyle): add Annotative toggle to the Dimension Style editor
Adds the annotative property (DsField::Annotative) to the dim-style edit
buffers, load/apply, and a checkbox on the Fit/Scale tab — consistent with
the Text Style editor's annotative toggle.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-03 17:49:38 +03:00
Hakan SevenandClaude Opus 4.8 52850947d2 feat(textstyle): full Text Style editor — big/TT font, fixed height, flags, annotative
Expands the Text Style manager beyond font/width/oblique: big-font and
TrueType font fields, fixed text height, Backward / Upside-down flags, and
an Annotative toggle (applied live). Bumps acadrust for the annotative
field.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-03 17:43:12 +03:00
Hakan SevenandClaude Opus 4.8 c1b33677e2 feat(fonts): switch the text engine from CXF to LibreCAD LFF fonts
Replace the small QCAD CXF stroke-font set with the full LibreCAD LFF font
library (46 fonts) and a new LFF parser/engine in src/scene/lff.rs. The
parser reads the `[hex] char` glyph blocks, tessellates `,A<bulge>` arcs, and
resolves `C<hex>` glyph references. Per LibreCAD's RS_Polyline convention a
vertex's bulge curves the segment ending at that vertex — getting this wrong
turned round letters like O into sideways capsules.

Font name resolution mirrors LibreCAD: match by file stem, map common
AutoCAD/DXF SHX names (txt, isocp, complex, italic, gothic*, gost, …) to the
nearest LFF family, and fall back to `standard`. A missing glyph in the chosen
family falls back to the broad `unicode` font so accented/Cyrillic/Greek text
still renders. Cap height stays 9 units, so the text scale is unchanged.

All text consumers move from cxf:: to lff::; complex linetypes still render
embedded text but no longer draw embedded shapes (LibreCAD ships no shape
file). The CXF module and every *.cxf asset are removed, and the MText / text
style font pickers list the LFF families.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-05-31 03:31:20 +03:00
Hakan Seven 5755c2e130 refactor(grip): square-only marker set + oriented stretch handles
Phase 1 of bringing the grip vocabulary in line with the standard
CAD convention: drop the per-position-type shape encoding (Diamond
for translate, Circle for parameter) and use a plain square for
every endpoint / vertex / centre grip. The behavioural midpoint vs
vertex distinction stays — it lives on `GripDef::is_midpoint` and
drives `Translate` vs `Absolute` in the grip-edit dispatcher — only
the marker shape collapses.

- `GripShape` keeps `Square`, `Rectangle`, `Triangle`. Diamond /
  Circle are gone.
- `GripDef` gains `dir: Option<[f32; 2]>` — a world-XY direction
  vector consumed by `Rectangle` to orient the box along its
  segment.
- `entities::common` exposes `square_grip`, `center_grip` (same
  square marker, flagged as translate), `rectangle_grip(id, world,
  dir)` for oriented mid-segment handles, and a kept-for-Phase-2
  `triangle_grip`.
- `overlay::GripMarker` / `grips_to_screen[_paper]` thread `dir`
  through to the canvas painter; the Rectangle path rotates the
  box around the grip centre using the world-XY direction (flipping
  the sin for screen-Y).

Every existing `diamond_grip(id, w)` call becomes `center_grip(id,
w)` — the visual change is square-replacing-diamond at line
midpoints / arc midpoints / circle centres / ellipse centres /
viewport / hatch loop centroids / dimension grips / image corners /
multileader / ray / underlay / ole2frame / solid3d.

`LwPolyline` grows a stretch handle on every segment (straight or
arc), drawn as the new oriented rectangle. The grip-edit path
translates both segment endpoints for straight segments and
adjusts the arc bulge from the new midpoint for arc segments.
2026-05-29 02:07:34 +03:00
Hakan Seven 1e33a9049c feat(grip): complete standard grip-shape vocabulary
Existing entity grip definitions already followed the conventional
CAD layout: square at vertices / endpoints, diamond at curve
centres / midpoints, triangle for directional control. Round out
the supported shape vocabulary with the two missing standards so
future entities (polyline straight-segment stretch grips, dimension
parameter grips, …) can pick the right marker without inventing
ad-hoc visuals:

- `GripShape::Rectangle` — direction-aware mid-segment stretch
  handle (wider-than-tall box).
- `GripShape::Circle` — parametric control (radius / dimension
  value).

New `rectangle_grip` / `circle_grip` helpers in `entities::common`
mirror the existing `square_grip` / `diamond_grip` / `triangle_grip`
constructors. `SelectionCanvas::draw` renders the two new variants;
the previously-used Square / Diamond / Triangle paths are
unchanged. Both new variants carry `#[allow(dead_code)]` until an
entity adopts them.
2026-05-29 01:46:33 +03:00
Hakan Seven 0ec6d77cb1 fix(snap): correct snap symbols + drop bogus midpoints on circles (#34)
Two bugs from #34:

1. Hovering a circle showed the Center snap as a diamond instead of
   the conventional circle outline.
2. Hovering a circle also showed Midpoint hits (triangle marker)
   even though a closed curve has no midpoint.

(2) came from a "tessellated curve" fallback in the Midpoint snap
path that produced a midpoint for every chord of the polyline
approximation. Drop that fallback — only entities with explicit
`key_vertices` (Line, LwPolyline) contribute per-segment midpoints
now. Curves that DO have a single well-defined midpoint (arcs, and
later splines) declare it explicitly via a new
`SnapHint::Midpoint`; `arc.rs` emits one at the arc-length centre.

(1) — and the broader "everything past Endpoint / Midpoint / Grid
was a diamond" inconsistency — fixed by giving every `SnapType` a
distinct marker in `SelectionCanvas::draw`:

- Center: hollow circle
- Node: circle with inscribed X
- Quadrant: diamond (unchanged)
- Intersection: X
- Apparent Intersection: X inside a square
- Insertion: two overlapping rectangles (tag glyph)
- Perpendicular: right-angle hook
- Tangent: circle with a bar across the top
- Nearest: hourglass / bowtie
- Extension: three dots
- Parallel: two parallel diagonal bars
- Endpoint / Midpoint / Grid: unchanged

Closes #34
2026-05-29 01:39:02 +03:00
Hakan Seven 8f9fe5226b fix(ribbon): clear blue tool state when its popup window closes (#40)
A ribbon tool that opens a popup window (LAYERS, PAGESETUP,
ABOUT, the style managers, …) marks itself blue via
\`activate_tool\` when the user clicks it, but nothing un-marked
the tool after the window was dismissed — \`OsWindowClosed\`
cleared the matching \`_window\` slot, the active-tool string
stayed put, and the button kept rendering as if the panel were
still open.

Add \`Ribbon::deactivate_tool_if(id)\` (clears only when the
active tool matches) and call it for every popup-window slot in
\`OsWindowClosed\`. Also clear inside the \`ToggleLayers\` close
branch — that path \`take()\`s \`layer_window\` to \`None\` before
\`OsWindowClosed\` fires, so the conditional in the
\`OsWindowClosed\` handler would miss the close otherwise.

Mapped IDs match the matching ribbon \`ToolDef.id\`s (LAYERS,
PAGESETUP, ABOUT) plus command names for the popups normally
opened via the command line (TEXTSTYLE, TABLESTYLE, MLSTYLE,
LAYOUTMANAGER / LAYOUTPANEL, PLOTSTYLE / STYLESMANAGER, DIMSTYLE,
SHORTCUTS / KEYBOARD) so a future ribbon tool with one of those
ids gets the same correct deactivate.

Closes #40
2026-05-29 01:23:25 +03:00
Hakan Seven 168f248593 fix(overlay): hide system cursor over viewport, drop CAD over divider
Two cursors layered on top of each other (the OS arrow / crosshair
icon plus the CAD crosshair drawn in `SelectionCanvas::draw`) looked
busy and made it harder to see what was pickable. `Interaction::None`
was the first try but `Stack::mouse_interaction` skips that value as
"no opinion" — the correct hide signal is `Interaction::Hidden`,
which iced_winit maps to a hidden cursor.

Over a Model-tile divider the OS now wins (resize arrow), and the CAD
crosshair is suppressed in `draw` via the same `tile_edge_under`
helper that mouse_interaction uses.
2026-05-28 19:52:34 +03:00
Hakan Seven 39eab9a4c4 feat(viewport): draggable Model-tile dividers
Tiled Model layouts now show the inner edges between panes as 2-px
dividers that act as resize grips: cursor on a divider → resize cue,
press + drag moves the edge (with every tile sharing that edge
updating together), release runs a collapse pass that absorbs any
tile that fell below the viewcube-comfort minimum into the neighbour
with the longest shared contact edge — drag a divider all the way
across to remove a pane.

- Scene grows `model_tile_edges`, `hit_model_tile_edge`,
  `move_model_tile_edge`, `collapse_small_model_tiles`. Edges are
  derived from the existing `model_tiles` rects (no extra storage).
- App carries a `tile_drag` Option; `ViewportLeftPress` starts it
  ahead of tile activation / picking, `ViewportMove` drives the
  edge, `ViewportLeftRelease` collapses + clears.
- `SelectionCanvas` draws the dividers and switches the cursor to
  `Resizing{Horizontally, Vertically}` over them.
2026-05-28 18:42:39 +03:00
Hakan SevenandClaude Opus 4.7 417a708275 feat(viewport): tile-relative input + overlays in unified model
Route every per-frame interaction through the active model tile's screen
rectangle so a tiled VPORTS layout behaves like independent panes while
still sharing one shader widget:

- pick / draw / snap / box+lasso: cursor mapped to tile-local space; the
  hover-activates-tile rule on ViewportMove keeps the active tile under
  the cursor, so the picked camera matches what the user sees.
- pan: switched to Camera::pan_screen(dx, dy, viewport_height) so the
  world-per-pixel rate matches the active tile's height instead of the
  full canvas.
- grid: clipped via Frame::with_clip to the active tile rect; world→screen
  adds the tile origin so the lines align with the panel.
- UCS icon: origin offset by the tile rect so the gizmo sits in the
  active tile's bottom-left corner.
- render-mode picker (+ split buttons) and ViewCube hit-area: positioned
  via active_model_tile_bounds with leading Spaces, mirroring the
  floating-viewport pattern.
- ViewCube hover: driven by the CursorMoved/ViewportMove handlers into a
  new Scene::viewcube_hover cell, so the highlight survives the cube
  hit-area overlay masking events from shader::Program::update.

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

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-27 17:49:23 +03:00
Hakan SevenandClaude Opus 4.7 4abde6001a feat(dyn-input): TAB-editable distance/angle/coordinate fields
Dinamik giriş artık cursor yanında düzenlenebilir kutular gösteriyor.
TAB ile kutular arası geçilir, bir kutuya yazınca o kutu kilitlenir
(değer sabitlenir), diğerleri cursor'ı takip etmeye devam eder, Enter
ile çözülen nokta komuta point-pick olarak iletilir.

- DocumentTab.dyn_fields / dyn_active state; DynComponent + DynFieldEntry
- sync_dyn_fields komutun dyn_field() + base noktasına göre kutu kümesini
  türetir: nokta+base → [d, açı], nokta+base yok → [X, Y], radius → [d],
  açı → [açı]
- klavye yönlendirme: rakam/./-/+ aktif kutuya, TAB sonraki kutuya,
  Enter try_dyn_commit, Backspace kilidi açar
- dyn_capturing iken command-line text alanı on_input'suz bırakılıyor
  ki focus'u ve tuşları çalmasın; girişler global key aboneliğinden
  geliyor (numpad dahil text alanı üzerinden yakalanıyor)
- çoklu-kutu overlay render: aktif kutu vurgulu, kilitli kutu farklı
  kenar rengi

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-27 14:08:57 +03:00
Hakan SevenandClaude Opus 4.7 2145ab8a66 feat(render): phase 0 — render-mode pick_list + 3-flag pipeline plumbing
Replaces the binary Wireframe/Solid toggle with a 7-mode dropdown
that maps onto acadrust's `ViewportRenderMode` enum: Wireframe 2D /
Wireframe 3D / Hidden Line / Flat Shaded / Gouraud Shaded / Flat
Shaded + Edges / Gouraud Shaded + Edges. Per-tab state lives on
`DocumentTab::render_mode`; the old `SetWireframe` message forwards
to `SetRenderMode` so the ribbon + WIREFRAME / SOLID command line
keep working.

`scene::render::render_mode_flags()` translates the mode into three
pipeline-facing booleans (`face3d_fill`, `mesh_fill`,
`show_3d_edges`); `mesh_fill` / `show_3d_edges` are stubs that the
upcoming phases will consume. `Primitive` carries the derived
`view_wireframe` plus the two new fields through to `prepare()`.

`Pipeline::upload_face3d` takes a `wireframe_only` flag that drops
3DFACE quad fills (built from `key_vertices`) while keeping the
`all_wires.fill_tris` channel — that channel carries text-LOD greek
rectangles and PolyfaceMesh face triangles which must stay visible
in wireframe mode. 3DFACE edges stay on regardless of mode.

Solid3D mesh wireframe rendering, Hidden Line z-prepass, and Flat /
Gouraud shader uniforms come in phases 1–4.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-27 00:08:37 +03:00
Hakan SevenandClaude Opus 4.7 05ea31aa2a feat(commandline): autocomplete suggestions + inventory-based registry
Type-as-you-go suggestion popup above the input that filters known
command names by substring (so `LEADER` surfaces both LEADER and
MLEADER). Up / Down navigates the list, Enter dispatches the
highlighted entry, clicking a row dispatches directly. Esc on a
non-empty input clears the buffer instead of escalating to
command-cancel.

The name corpus comes from `inventory::submit!` blocks placed next
to each `CadCommand` impl rather than a hand-maintained static list.
Adding a new interactive command means dropping one `inventory::submit!`
line in its own module file — the autocomplete picks it up at the
next compile. 98 submissions seeded across 60 module files;
`command::all_registered_command_names()` flattens them at runtime.

One-shot dispatch arms in `app/commands.rs` (NEW, OPEN, SAVE, UNDO,
…) don't have a `CadCommand` impl and are therefore absent from
autocomplete by design.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-26 22:45:54 +03:00
Hakan SevenandClaude Opus 4.7 4124cb2689 feat(commandline): full-history dropdown next to the input
Add a ▸/▾ toggle button on the right edge of the input row. Tapping
it pops up the full backlog of everything the command line has pushed
since startup — useful once the on-overlay rows have faded out.

The dropdown is a fixed-height scrollable panel rendered above the
input pill. `anchor_bottom` keeps the newest entry in view on open
and `opaque` blocks wheel events from bubbling through to the
viewport shader behind it (without it, scrolling the history zoomed
the drawing). Submitting a command closes the dropdown so the new
prompt is immediately visible.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-26 22:13:15 +03:00
Hakan SevenandClaude Opus 4.7 5a8c79deb5 feat(commandline): fade history entries off the overlay after 3 s
The overlay used to keep the last four history lines on screen
indefinitely, leaving stale command output cluttering the viewport.
Stamp each `HistoryEntry` with its `Instant` of insertion and filter
the rows shown on the overlay to entries younger than 3 s.

`CommandLine::has_visible_history()` gates a per-frame tick
subscription so the view re-renders and the entry disappears
on time. The subscription auto-stops once no entry is fresh enough,
keeping the idle CPU draw at zero (#18).

Full history stays in the backing `Vec` — the upcoming dropdown
button will surface it on demand.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-26 19:28:09 +03:00