From 8f02e1ca07dcfcb207a519e574d21a86f177e381 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Fri, 29 May 2026 00:57:37 +0300 Subject: [PATCH] fix(dyn-input): re-sync fields immediately after point commits (#35) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `sync_dyn_fields` only ran during `ViewportMove`, so a typed-coord or click-driven point commit left the previous iteration's field shape in place until the user nudged the mouse. After the first LINE click that meant the stale `[X, Y]` (built when there was no base) kept serving the next point's input as cartesian even though the command-default for a "Point with base" is now polar `[Distance, Angle]`. The original #35 fix preserved a `,`-reshaped cartesian set on purpose, but the same machinery now also held onto a never-explicitly-chosen `[X, Y]` carried over from "no base" → "has base". Track that intent explicitly with `dyn_user_reshaped` (set in `dyn_comma_advance`, cleared on point commit and command start) and only treat a non-matching shape as acceptable while that flag is on. Re-run `sync_dyn_fields` from every point-commit path (command-line typed coord, mouse click, dynamic-input locked commit) so the freshly updated `has_base` state immediately picks the right default and the user sees polar fields without having to move the mouse first. --- src/app/commands.rs | 3 +++ src/app/mod.rs | 7 +++++++ src/app/update.rs | 42 ++++++++++++++++++++++++++++++------------ 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/app/commands.rs b/src/app/commands.rs index 45fcfa243..97ded0c70 100644 --- a/src/app/commands.rs +++ b/src/app/commands.rs @@ -15,6 +15,9 @@ impl OpenCADStudio { // Reset the last committed point so the first click of the new command // is not constrained by ortho/polar relative to a previous command's endpoint. self.last_point = None; + // A fresh command starts at the polar/cartesian default — clear + // any `,`-driven reshape from a previous command (#35). + self.dyn_user_reshaped = false; if let Some(path_str) = cmd.strip_prefix("OPEN_RECENT:") { let path = PathBuf::from(path_str); diff --git a/src/app/mod.rs b/src/app/mod.rs index 1e239d03c..19b627e8e 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -88,6 +88,12 @@ pub(super) struct OpenCADStudio { /// edge, updated on move, cleared on release (which also runs the /// collapse pass). tile_drag: Option, + /// `true` once the user has reshaped the dynamic-input field set via + /// the `,` separator during the current command iteration. Tells + /// `sync_dyn_fields` to preserve the user's chosen shape instead of + /// reverting to the command-default when `has_base` flips. Cleared + /// on point commit / command start. See #35. + dyn_user_reshaped: bool, /// Show the UCS icon in the bottom-left corner of model space (UCSICON). show_ucs_icon: bool, /// Whether the ViewCube 3D gizmo is visible in model space (NAVVCUBE). @@ -763,6 +769,7 @@ impl OpenCADStudio { dyn_input: true, awaiting_vports: false, tile_drag: None, + dyn_user_reshaped: false, show_ucs_icon: true, show_viewcube: true, show_properties: true, diff --git a/src/app/update.rs b/src/app/update.rs index 030fdb8a4..1184f982c 100644 --- a/src/app/update.rs +++ b/src/app/update.rs @@ -1097,6 +1097,8 @@ impl OpenCADStudio { } }; self.last_point = Some(wcs_pt); + self.dyn_user_reshaped = false; + self.sync_dyn_fields(); let result = self.tabs[i].active_cmd.as_mut().map(|c| c.on_point(wcs_pt)); if let Some(r) = result { let task = self.apply_cmd_result(r); @@ -2476,6 +2478,8 @@ impl OpenCADStudio { } } else { self.last_point = Some(world_pt); + self.dyn_user_reshaped = false; + self.sync_dyn_fields(); self.tabs[i] .active_cmd .as_mut() @@ -5400,19 +5404,28 @@ impl OpenCADStudio { // move. let current: Vec = self.tabs[i].dyn_fields.iter().map(|f| f.component).collect(); - let current_is_acceptable = match field { - crate::command::DynField::Distance => { - matches!(current.as_slice(), [DynComponent::Distance]) + // Only treat a cartesian / polar variant as "good enough to keep" + // when the user explicitly reshaped via `,`. Otherwise we follow + // the command's default so e.g. clicking the first point of LINE + // flips a stale `[X, Y]` (from before there was a base) over to + // the polar `[Distance, Angle]` the prompt actually wants. + let current_is_acceptable = if self.dyn_user_reshaped { + match field { + crate::command::DynField::Distance => { + matches!(current.as_slice(), [DynComponent::Distance]) + } + crate::command::DynField::Angle => { + matches!(current.as_slice(), [DynComponent::Angle]) + } + crate::command::DynField::Point => matches!( + current.as_slice(), + [DynComponent::Distance, DynComponent::Angle] + | [DynComponent::X, DynComponent::Y] + | [DynComponent::X, DynComponent::Y, DynComponent::Z] + ), } - crate::command::DynField::Angle => { - matches!(current.as_slice(), [DynComponent::Angle]) - } - crate::command::DynField::Point => matches!( - current.as_slice(), - [DynComponent::Distance, DynComponent::Angle] - | [DynComponent::X, DynComponent::Y] - | [DynComponent::X, DynComponent::Y, DynComponent::Z] - ), + } else { + current == default }; if !current_is_acceptable { self.tabs[i].dyn_fields = default.into_iter().map(DynFieldEntry::new).collect(); @@ -5523,6 +5536,9 @@ impl OpenCADStudio { if self.tabs[i].dyn_fields.is_empty() { return; } + // The user picked a shape — `sync_dyn_fields` preserves it until + // the next commit / command-start clears the flag. + self.dyn_user_reshaped = true; let active = self .tabs[i] .dyn_active @@ -5582,6 +5598,8 @@ impl OpenCADStudio { } let pt = self.dyn_resolve_point()?; self.last_point = Some(pt); + self.dyn_user_reshaped = false; + self.sync_dyn_fields(); let result = self.tabs[i].active_cmd.as_mut().map(|c| c.on_point(pt)); for f in self.tabs[i].dyn_fields.iter_mut() { f.buffer = None;