From 64c35cadff4b5d855d27c759b9d0bac8d2a76723 Mon Sep 17 00:00:00 2001 From: Antoine Boxho Date: Sat, 24 Oct 2026 06:51:36 +0100 Subject: [PATCH] Distinguish polyline midpoint grips from vertices (#1950) (#1958) * ui: distinguish polyline midpoint grips * docs: the midpoint-grip row belongs in the revision history (CodeRabbit) Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Brandon Thomas Co-authored-by: Claude Opus 5.5 --- crates/ui-egui/src/canvas.rs | 21 ++++++++++++++++----- docs/ui-parity.md | 5 +++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index 1004cc28..390c40a1 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -1937,10 +1937,12 @@ pub fn show(app: &mut CadApp, ui: &mut egui::Ui) { let gs = app.session.settings.gripsize as f32; for h in sel.iter().take(200) { if let Some(e) = st.doc.entity(*h) { - for (gi, g) in e.kind.grips().into_iter().enumerate() { + let grips = e.kind.grips(); + let count = grips.len(); + for (gi, g) in grips.into_iter().enumerate() { let sp = xf.to_screen(g); if rect.contains(sp) { - let r = Rect::from_center_size(sp, vec2(gs * 2.0, gs * 2.0)); + let r = grip_rect(&e.kind, count, gi, sp, gs); let hot = app.canvas.hot_grips.contains(&(*h, gi)); let warm = !hot && hover_pos.is_some_and(|hp| r.expand(2.0).contains(hp)); painter.rect_filled( @@ -2668,11 +2670,18 @@ fn grip_menu(app: &mut CadApp, resp: &egui::Response) { } } +/// Polyline segment midpoint grips are rectangular; vertex grips remain square. +fn grip_rect(kind: &cadcraft_doc::EntityKind, count: usize, index: usize, center: Pos2, size: f32) -> Rect { + // The grip list interleaves vertices and available segment midpoints, then any remaining vertices. + let midpoint = matches!(kind, cadcraft_doc::EntityKind::LwPolyline(p) if index % 2 == 1 && index / 2 < count.saturating_sub(p.vertices.len())); + Rect::from_center_size(center, vec2(size * 2.0, if midpoint { size } else { size * 2.0 })) +} + /// The grip of a selected object under the cursor, if any: (object, grip index). fn grip_at(app: &CadApp, xf: &Xf, hover: Option) -> Option<(Handle, usize)> { let hp = hover?; let st = app.session.state().ok()?; - let gs = app.session.settings.gripsize as f32 + 3.0; + let gs = app.session.settings.gripsize as f32; let sel = app.session.selection(); if !app.session.shows_grips(sel.len()) { return None; @@ -2682,9 +2691,11 @@ fn grip_at(app: &CadApp, xf: &Xf, hover: Option) -> Option<(Handle, usize) if st.doc.layer(&e.common.layer).is_some_and(|l| l.locked) { continue; } - for (i, g) in e.kind.grips().into_iter().enumerate() { + let grips = e.kind.grips(); + let count = grips.len(); + for (i, g) in grips.into_iter().enumerate() { let sp = xf.to_screen(g); - if (sp.x - hp.x).abs() <= gs && (sp.y - hp.y).abs() <= gs { + if grip_rect(&e.kind, count, i, sp, gs).expand(3.0).contains(hp) { return Some((*h, i)); } } diff --git a/docs/ui-parity.md b/docs/ui-parity.md index d0c3fd1e..c06e8f24 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -1,6 +1,6 @@ # UI parity -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-13 · **Change:** minor (stable dash anchors on filled-object highlights) · **Target:** Autodesk AutoCAD 2027 for Mac (26.0) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-22 · **Change:** minor (distinct polyline midpoint grips) · **Target:** Autodesk AutoCAD 2027 for Mac (26.0) How CADCraft's interaction compares with AutoCAD's: point entry, object snaps, tracking, dynamic input, grips, selection, the command line, chrome and navigation. A drafter's speed in AutoCAD @@ -119,7 +119,7 @@ down-arrow options menu (DYNPROMPT), and DYNDIM. | Multifunctional grip hover menus (Add Vertex, Remove Vertex, Convert to Arc, Lengthen …) | yes | **no** | | Grip dimensional input (length/angle fields) | yes | no | | Dynamic block grips | yes | no (no dynamic blocks) | -| Grip appearance (GRIPSIZE, colours, hover) | yes | GRIPSIZE, GRIPS and GRIPOBJLIMIT honoured (Options ▸ Selection); no grip colours | +| Grip appearance (GRIPSIZE, colours, hover) | yes | GRIPSIZE, GRIPS and GRIPOBJLIMIT honoured (Options ▸ Selection); polyline segment midpoints use rectangles, vertices use squares; no grip colours | ## Selection (≈ 40%) @@ -203,6 +203,7 @@ down-arrow options menu (DYNPROMPT), and DYNDIM. | Date | Change | Summary | |---|---|---| +| 2026-10-22 | minor | Polyline segment midpoint grips use rectangles, distinct from square vertex grips, with matching hover and pick bounds (#1950) | | 2026-10-13 | minor | Filled-region highlight boundaries are traversed in deterministic coordinate order, fixing dash-phase jumps on CPU hover/selection redraws and GPU highlight rebuilds; CPU dash-position, pixel and GPU mesh regressions | | 2026-10-14 | minor | Selection cycling (#1143): the list and badge of SELECTIONCYCLING, Shift+Space through overlapping objects (#1145) | | 2026-10-14 | minor | Hatch Edit dialog adds boundaries from picked points or closed objects and removes selected loops |