diff --git a/src/app/mod.rs b/src/app/mod.rs index bf17d5032..f38fb04be 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1458,6 +1458,8 @@ pub enum Message { ToggleLayoutList, /// Close the Model/layout list dropdown. CloseLayoutList, + /// Cycle the coordinate readout mode ($COORDS): static → live → polar. + CycleCoordsMode, /// Toggle the status-bar customization menu open/closed. ToggleStatusBarMenu, /// Close the status-bar customization menu. diff --git a/src/app/update/mod.rs b/src/app/update/mod.rs index eb0f7d566..1b7cc8519 100644 --- a/src/app/update/mod.rs +++ b/src/app/update/mod.rs @@ -1541,6 +1541,26 @@ impl OpenCADStudio { } Task::none() } + Message::CycleCoordsMode => { + // $COORDS 0 (static) → 1 (live absolute) → 2 (polar) → 0. + let i = self.active_tab; + if i < self.tabs.len() { + let mode = { + let h = &mut self.tabs[i].scene.document.header; + h.coords_mode = (h.coords_mode + 1).rem_euclid(3); + h.coords_mode + }; + self.tabs[i].dirty = true; + let label = match mode { + 0 => "static", + 2 => "polar", + _ => "live", + }; + self.command_line + .push_output(&format!("COORDS = {mode} ({label})")); + } + Task::none() + } Message::TogglePolar => { self.polar_mode ^= true; if self.polar_mode { diff --git a/src/app/view/mod.rs b/src/app/view/mod.rs index 5337e59b5..021669d6f 100644 --- a/src/app/view/mod.rs +++ b/src/app/view/mod.rs @@ -1303,16 +1303,21 @@ impl OpenCADStudio { // drawing coordinates (paper space carries no offset), then // report it in the active UCS — the readout follows the // user's coordinate system, not raw WCS (no-op without UCS). - let cursor_coord = { - let lc = tab.last_cursor_world; + let to_readout = |p: glam::Vec3| { // The readout follows the active pane's UCS — model space // or inside a floating viewport (no-op without a UCS). if tab.editing_model_space() { - tab.ucs_xform().to_ucs(lc) + tab.ucs_xform().to_ucs(p) } else { - lc + p } }; + let cursor_coord = to_readout(tab.last_cursor_world); + // The last picked point (same UCS as the cursor) drives the + // static ($COORDS 0) and polar ($COORDS 2) readouts. + let last_coord = self.last_point.map(to_readout); + let coords_mode = tab.scene.document.header.coords_mode; + let picking = tab.active_cmd.is_some(); self.status_bar.view( &self.snapper, self.snap_popup_open, @@ -1334,6 +1339,9 @@ impl OpenCADStudio { scale_pill_enabled, tab.scene.document.header.lineweight_display, cursor_coord, + coords_mode, + last_coord, + picking, self.clean_screen, tab.scene.document.header.insertion_units, self.units_popup_open, diff --git a/src/ui/statusbar/mod.rs b/src/ui/statusbar/mod.rs index 9df3a7c9c..02d258c90 100644 --- a/src/ui/statusbar/mod.rs +++ b/src/ui/statusbar/mod.rs @@ -79,6 +79,13 @@ impl StatusBar { lineweight_display: bool, // Live cursor position in model coordinates, for the coordinate readout. cursor_world: glam::Vec3, + // $COORDS readout mode: 0 = static (updates only on a pick), 1 = live + // absolute, 2 = polar (distance, + // True while a command is prompting for a point (enables the polar readout). + picking: bool, // True while clean-screen mode hides the ribbon and side panels. clean_screen: bool, // Drawing units (INSUNITS) for the units pill. @@ -153,10 +160,11 @@ impl StatusBar { let vis = |p: StatusPill| config.is_visible(p); let mut pills: Vec> = Vec::new(); if vis(StatusPill::Coords) { + let coords_label = format_coords(cursor_world, last_point, coords_mode, picking); pills.push( tip( - status_pill(format_coords(cursor_world)).into(), - "Cursor coordinates (X, Y, Z)", + popup_pill(&coords_label, false, Message::CycleCoordsMode), + "Cursor coordinates ($COORDS)\nClick to cycle: static / live / polar", ) .into(), ); @@ -377,8 +385,28 @@ impl StatusBar { // ── Coordinate readout ──────────────────────────────────────────────────── -fn format_coords(p: glam::Vec3) -> String { - format!("{:.4}, {:.4}, {:.4}", p.x, p.y, p.z) +fn format_coords(cursor: glam::Vec3, last: Option, mode: i16, picking: bool) -> String { + let abs = |p: glam::Vec3| format!("{:.4}, {:.4}, {:.4}", p.x, p.y, p.z); + match mode { + // Static: show the last picked point; the readout freezes between picks. + 0 => abs(last.unwrap_or(cursor)), + // Polar: distance < angle relative to the last point while a command is + // prompting for a point; absolute otherwise. + 2 => match (picking, last) { + (true, Some(l)) => { + let d = cursor - l; + let dist = (d.x * d.x + d.y * d.y).sqrt(); + let mut ang = d.y.atan2(d.x).to_degrees(); + if ang < 0.0 { + ang += 360.0; + } + format!("{dist:.4} < {ang:.2}\u{b0}") + } + _ => abs(cursor), + }, + // 1 (default) and anything else: live absolute. + _ => abs(cursor), + } } // ── Customization handle ──────────────────────────────────────────────────