fix(dyn-input): re-sync fields immediately after point commits (#35)

`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.
This commit is contained in:
Hakan Seven committed 2026-05-29 00:57:37 +03:00
1 parent f952fc9bb7
commit 8f02e1ca07
3 files changed
+40 -12

No files matched your search

+3
View File
@@ -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);
+7
View File
@@ -88,6 +88,12 @@ pub(super) struct OpenCADStudio {
/// edge, updated on move, cleared on release (which also runs the
/// collapse pass).
tile_drag: Option<TileDrag>,
/// `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,
+30 -12
View File
@@ -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<DynComponent> =
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;