2026-03-22 14:56:27 +03:00
|
|
|
// Shared value types used by the dispatch and grip systems.
|
|
|
|
|
|
|
|
|
|
use acadrust::types::{Color as AcadColor, LineWeight};
|
|
|
|
|
use glam::Vec3;
|
|
|
|
|
|
|
|
|
|
/// The kind of value held by a property row.
|
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
|
|
|
pub enum PropValue {
|
|
|
|
|
/// Read-only display text.
|
|
|
|
|
ReadOnly(String),
|
|
|
|
|
/// Editable numeric/text field.
|
|
|
|
|
EditText(String),
|
|
|
|
|
/// Layer name — rendered as a combo_box.
|
|
|
|
|
LayerChoice(String),
|
|
|
|
|
/// Generic string choice rendered as a combo_box.
|
|
|
|
|
Choice {
|
|
|
|
|
selected: String,
|
|
|
|
|
options: Vec<String>,
|
|
|
|
|
},
|
|
|
|
|
/// ACI/RGB/ByLayer/ByBlock color — rendered as a color picker.
|
|
|
|
|
ColorChoice(AcadColor),
|
|
|
|
|
/// Color varies across the current multi-selection.
|
|
|
|
|
ColorVaries,
|
|
|
|
|
/// Line weight — rendered as a combo_box.
|
|
|
|
|
LwChoice(LineWeight),
|
|
|
|
|
/// Lineweight varies across the current multi-selection.
|
|
|
|
|
LwVaries,
|
|
|
|
|
/// Linetype name — rendered as a combo_box.
|
|
|
|
|
LinetypeChoice(String),
|
|
|
|
|
/// Boolean flag — rendered as a toggle button (e.g. Invisible).
|
|
|
|
|
BoolToggle { field: &'static str, value: bool },
|
|
|
|
|
/// Hatch pattern name — rendered as a combo_box from the catalog.
|
|
|
|
|
HatchPatternChoice(String),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A single property row in the Properties panel.
|
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
|
|
|
pub struct Property {
|
|
|
|
|
pub label: String,
|
|
|
|
|
/// Stable field identifier used in `PropGeomInput` / `PropGeomCommit` messages.
|
|
|
|
|
pub field: &'static str,
|
|
|
|
|
pub value: PropValue,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A named section of properties (e.g. "General", "Geometry").
|
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
|
|
|
pub struct PropSection {
|
|
|
|
|
pub title: String,
|
|
|
|
|
pub props: Vec<Property>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Grip types ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
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
|
|
|
/// Visual marker shape for a grip point. The complete vocabulary that
|
|
|
|
|
/// matches the standard CAD grip conventions:
|
|
|
|
|
/// * `Square` — endpoint / vertex / centre. Drag → moves a single
|
|
|
|
|
/// point or translates the entity.
|
|
|
|
|
/// * `Rectangle` — direction-aware mid-segment stretch handle.
|
|
|
|
|
/// Drawn as a small box rotated along `dir` (the in-plane segment
|
|
|
|
|
/// direction in world XY). Used for polyline / wipeout / image /
|
|
|
|
|
/// dimension segment midpoints.
|
|
|
|
|
/// * `Triangle` — directional indicator (Phase 2: dynamic-block
|
|
|
|
|
/// parameters, dimension reverse-arrow flips, multi-functional
|
|
|
|
|
/// hover popups).
|
2026-03-22 14:56:27 +03:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
2026-05-29 01:46:33 +03:00
|
|
|
#[allow(dead_code)]
|
2026-03-22 14:56:27 +03:00
|
|
|
pub enum GripShape {
|
|
|
|
|
Square,
|
2026-05-29 01:46:33 +03:00
|
|
|
Rectangle,
|
2026-03-22 14:56:27 +03:00
|
|
|
Triangle,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Describes one grip point for an entity.
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
|
pub struct GripDef {
|
|
|
|
|
/// Object-local identifier (stable index, unique per object instance).
|
|
|
|
|
pub id: usize,
|
|
|
|
|
/// World-space position of the grip.
|
|
|
|
|
pub world: Vec3,
|
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
|
|
|
/// `true` → midpoint / centre grip (drags the whole shape).
|
|
|
|
|
/// `false` → endpoint / vertex grip (moves a single point).
|
2026-03-22 14:56:27 +03:00
|
|
|
pub is_midpoint: bool,
|
|
|
|
|
/// Visual marker shape for the grip.
|
|
|
|
|
pub shape: GripShape,
|
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
|
|
|
/// World-XY direction vector used to orient a `Rectangle` grip
|
|
|
|
|
/// along its segment. `None` for shapes that don't need rotation
|
|
|
|
|
/// (Square, Triangle in non-directional contexts).
|
|
|
|
|
pub dir: Option<[f32; 2]>,
|
2026-03-22 14:56:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// How to apply a grip drag result.
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
|
pub enum GripApply {
|
|
|
|
|
/// Move a specific vertex to this absolute world position.
|
|
|
|
|
Absolute(Vec3),
|
|
|
|
|
/// Translate the whole object by this delta vector.
|
|
|
|
|
Translate(Vec3),
|
|
|
|
|
}
|
feat(grip): multi-functional hover popup menu
Phase 2 of the grip overhaul: when the cursor dwells on a selected
entity's grip the overlay opens a popup menu with entity-specific
options (Stretch / Add Vertex / Remove Vertex / Convert to
Arc-Line / …). Picking an item dispatches `apply_grip_menu`; the
default `Stretch` entry is a no-op that lets the user click the
grip to start the normal drag.
- `GripMenuItem` + `GripMenuAction` (full vocabulary covering
stretch, add/remove vertex, convert to arc/line, reverse arrows,
text-position variants, hatch parameters, tangent direction).
- `Grippable` trait gains `grip_menu` + `apply_grip_menu` with
trait-default `Stretch`-only impls so every existing entity gets
the popup for free.
- `EntityTypeOps` dispatches both methods across the same entity
list as the existing grip / property machinery.
- `OpenCADStudio` carries `grip_hover` (dwell tracker) +
`grip_popup` (open menu). `update_grip_hover` runs from
`ViewportMove`: hit-tests grips, refreshes the dwell timer, and
opens the popup after 600 ms. Cursor drift past 80 px or a grip
click dismisses it.
- `view.rs` paints the popup as an absolute-positioned column of
buttons at the grip's screen anchor; each button publishes
`Message::GripMenuPick(idx)`.
- `LwPolyline` overrides `Grippable` manually (skips the standard
macro) so its vertex grip exposes Add/Remove Vertex and its
segment-midpoint grip exposes Add Vertex + Convert to Arc/Line.
`apply_grip_menu` performs the edits: vertex insertion at the
chord midpoint inheriting the previous bulge, vertex removal,
and bulge toggle for the arc/line conversion.
2026-05-29 09:30:54 +03:00
|
|
|
|
|
|
|
|
/// One entry in the hover-popup menu that opens when the cursor dwells
|
|
|
|
|
/// on a grip. The `label` is the user-visible string; `action` is the
|
|
|
|
|
/// operation the entity will perform when the item is committed.
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
|
|
|
pub struct GripMenuItem {
|
|
|
|
|
pub label: &'static str,
|
|
|
|
|
pub action: GripMenuAction,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// All operations a grip popup menu can dispatch. Entity-specific code
|
|
|
|
|
/// in `apply_grip_menu` decodes these into edits. `Stretch` is the
|
|
|
|
|
/// default no-op-equivalent — picking it just starts the regular
|
|
|
|
|
/// stretch drag, identical to clicking the grip with no popup open.
|
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
|
|
|
pub enum GripMenuAction {
|
|
|
|
|
Stretch,
|
|
|
|
|
Lengthen,
|
|
|
|
|
Radius,
|
|
|
|
|
ArcLength,
|
|
|
|
|
AddVertex,
|
|
|
|
|
RemoveVertex,
|
|
|
|
|
ConvertToArc,
|
|
|
|
|
ConvertToLine,
|
|
|
|
|
StretchVertex,
|
|
|
|
|
AddLeader,
|
|
|
|
|
RemoveLeader,
|
|
|
|
|
ReverseArrows,
|
|
|
|
|
MoveWithDimLine,
|
|
|
|
|
MoveWithLeader,
|
|
|
|
|
MoveIndependent,
|
|
|
|
|
ResetText,
|
|
|
|
|
RotateText,
|
|
|
|
|
AboveDimLine,
|
|
|
|
|
Center,
|
|
|
|
|
OriginPoint,
|
|
|
|
|
HatchAngle,
|
|
|
|
|
HatchScale,
|
|
|
|
|
HatchPattern,
|
|
|
|
|
TangentDirection,
|
|
|
|
|
}
|