feat(dynamic-input): shared angle reference + sign handling

Make angle display, sign and the polar guide reference part of the
common infrastructure instead of per-command logic:

- DynSpec.ref_point now drives the polar guide's reference direction, so
  the arc and value box can sweep from a command-defined reference (not
  just +X). LINE etc. keep +X by leaving it None.
- `dyn_display_angle_deg` is the single rule for how an angle reads: the
  unsigned magnitude of the short angle, so clockwise (cursor on the CW
  side of the reference) shows positive. Used by the generic value box,
  ROTATE and ARC.
- A typed angle committed via on_text_input is re-signed by the cursor's
  side relative to the reference (`dyn_sign_angle_text`), so commands
  receive an already-signed value and don't each implement it.

ROTATE: drop its own sweep arc (the polar guide draws it now, anchored at
the centre and swept from the reference); the rotation commits in the
dragged direction whether picked, typed or accepted with Enter.

ARC SCA/CSA: reference the start angle so the arc, sign and readout are
all relative to it.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-06-15 23:03:08 +03:00
1 parent 40a52cea79
commit 1a9844b134
6 files changed
+137 -66

No files matched your search

+17
View File
@@ -283,6 +283,23 @@ pub enum DynRole {
Count,
}
/// Shared rule for how an angle reads in the dynamic-input box: the unsigned
/// magnitude of the short signed angle, so a clockwise angle (cursor below the
/// reference axis) shows as a positive value rather than a negative or a
/// CCW 300-something. Callers keep the *signed* radian for the actual
/// computation/commit; this is display-only. `signed_rad` is the angle from
/// the reference to the cursor.
pub fn dyn_display_angle_deg(signed_rad: f32) -> f32 {
let mut a = signed_rad % std::f32::consts::TAU;
if a > std::f32::consts::PI {
a -= std::f32::consts::TAU;
}
if a <= -std::f32::consts::PI {
a += std::f32::consts::TAU;
}
a.to_degrees().abs()
}
impl DynRole {
/// Default label shown before the value (empty = value only).
pub fn label(self) -> &'static str {