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>
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>
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>
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 <noreply@anthropic.com>
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.
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.
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
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.
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.
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
Replace the flat fixed-length axis arrows with a proper 3D tripod:
- Axis lengths are proportional (longest fills UCS_ICON_LEN, shorter
axes stay foreshortened) giving real depth perception as the camera
rotates
- Draw order computed from NDC Z so back axes render behind front ones
- X / Y / Z labels rendered beyond each arrowhead tip
- All axes drawn at full opacity with solid filled arrowheads
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Hide OS crosshair and drawn crosshair when cursor is over ViewCube area
- Enhanced hover glow in WGSL shader (blue tint + brightness boost)
- Fixed region_centroids() Y-axis sign for all FRONT/BACK-related regions
- Swapped corner geometry assignments (TPF↔TBK, BTF↔BBK) to match
intended FRONT/BACK semantics (sy=-1 = FRONT, sy=+1 = BACK)
- Corrected all snap_angles: yaw_pitch_to_quat(0,0) places eye at -Y
(FRONT view), so FRONT=0 and BACK=PI — cascaded through edges/corners
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Viewport right-click now shows a proper widget-based context menu:
- When a command is active: Cancel / Enter
- Otherwise: Repeat last commands, Delete/Move/Copy (if selected),
Select All, Zoom Extents
CONSTRUCTIONLINE added as an alias for XLINE (XL).
Canvas-drawn placeholder removed; context menu closes on Escape,
click-outside, or when any action is taken.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- snap/mod.rs: Snapper gains otrack_enabled, tracking_points, dwell state;
update_otrack_dwell() acquires a snap point after DWELL_THRESHOLD=4
consecutive moves near the same position; otrack_snap() returns an
H/V alignment snap position; clear_tracking() resets state on command end
- overlay.rs: selection_overlay accepts ost_points + cursor_screen;
draws light-blue dashed H/V lines from acquired points + small cross marker
- statusbar.rs: OTRACK pill (F11) added next to DYN
- view.rs: projects tracking_points to screen, passes to selection_overlay
- update.rs: calls update_otrack_dwell + otrack_snap in ViewportMove;
overrides effective point with OST alignment when no normal snap is active
- ROADMAP.md: Object Snap Tracking marked ✅
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- overlay.rs: dynamic_input_overlay() canvas widget draws a semi-transparent
coordinate tooltip near the cursor; shows X/Y in absolute mode or
dist/angle relative to last_point when a command base point exists
- statusbar: DYN toggle pill with F12 tooltip (calls ToggleDynInput)
- app/mod.rs: dyn_input: bool field (default true), ToggleDynInput message
- view.rs: builds DYN label and pushes overlay into viewport_stack when
dyn_input=true and a command is active
- document.rs: last_cursor_screen: iced::Point — updated on every ViewportMove
- ROADMAP.md: Dynamic Input overlay marked ✅
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Grid snap (F9):
• snap spacing now tracks the visible grid zoom level — computed via
compute_grid_step() (same adaptive pow-of-5 logic as draw_grid),
updated on every ViewportMove so zooming in/out keeps snap aligned
with the grid lines on screen
Polar tracking (F10):
• configurable angle increment stored in polar_increment_deg (default 45°)
• right-click the POLAR pill to cycle through 15 → 30 → 45 → 90°
• pill label shows current angle ("POLAR 45°")
• visual guide line: while drawing with polar on, a dashed cyan line is
drawn from last_point along the snapped direction across the viewport
• SetPolarAngle message + handler; all polar_constrain() calls use the
stored increment instead of the hardcoded 45°
ROADMAP updated: Grid snap and Polar tracking marked ✅.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Before layout completes the viewport bounds are 0×0, causing project_point3
to produce NaN/Inf coordinates which panicked in lyon_path assertions.
Added early-return when bounds < 10px, and finite checks on all projected
and derived coordinates before calling any canvas drawing functions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Screen-space UCS icon drawn on the existing selection canvas overlay.
Axes are projected from world space so the icon rotates with the camera,
always showing the correct X/Y/Z orientation relative to the drawing plane.
Each axis has its canonical color (X=red, Y=green, Z=blue) with arrowheads.
Icon visibility controlled by show_ucs_icon flag (default on); toggled by
UCSICON ON/OFF command which also updates paper-space viewport entities.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>