forked from 1b-agent/opencadstudio-upstream
fix(extrude): typed height is ignored on web (#1082)
On wasm the canvas holds focus, so a typed value reaches the dynamic Distance field through CommandAppendChar+CommandFinalize — and try_dyn_commit only commits as text when wants_text() && ! point_step_accepts_keywords(), or dyn_commit_as_text(). EXTRUDE's Height step accepts keywords and never overrode dyn_commit_as_text (unlike PRESSPULL and REVOLVE), so the value resolved as an in-plane point whose height is ~0 and silently re-prompted. Commit the Height step as text, matching its siblings; regression test drives the exact web message sequence.
This commit is contained in:
1 parent
a60b52a462
commit
9e4c3837dd
2 files changed
+101
No files matched your search
@@ -1680,4 +1680,95 @@ mod tests {
|
||||
let _ = app.update(Message::ToggleRibbonDropdown("PROP_COLOR".to_string()));
|
||||
let _ = app.view(wid);
|
||||
}
|
||||
|
||||
/// Regression test for issue #1082: a height typed while EXTRUDE waits at
|
||||
/// its Height prompt must extrude, including when the keystrokes arrive
|
||||
/// through the global key-press subscription (`CommandAppendChar` → the
|
||||
/// dynamic-input field buffer → `CommandFinalize`) instead of the focused
|
||||
/// command-line widget (`CommandInput` → `CommandSubmit`). The former is
|
||||
/// the only route on the web build, where the canvas — not the command
|
||||
/// line — holds keyboard focus.
|
||||
#[test]
|
||||
fn extrude_typed_height_from_dyn_field() {
|
||||
use crate::app::Message;
|
||||
let mut app = OpenCADStudio::new_for_test();
|
||||
app.automation_op(r#"{"op":"new"}"#);
|
||||
// A closed rectangle in the XY plane.
|
||||
use acadrust::entities::LwVertex;
|
||||
use acadrust::types::Vector2;
|
||||
let rect = acadrust::LwPolyline {
|
||||
vertices: [
|
||||
(-10.0, -10.0),
|
||||
(10.0, -10.0),
|
||||
(10.0, 10.0),
|
||||
(-10.0, 10.0),
|
||||
]
|
||||
.iter()
|
||||
.map(|(x, y)| LwVertex::new(Vector2::new(*x, *y)))
|
||||
.collect(),
|
||||
is_closed: true,
|
||||
..Default::default()
|
||||
};
|
||||
let handle = app.tabs[0]
|
||||
.scene
|
||||
.document
|
||||
.add_entity(acadrust::EntityType::LwPolyline(rect))
|
||||
.unwrap();
|
||||
|
||||
// Start EXTRUDE via the command line.
|
||||
let _ = app.update(Message::CommandInput("EXTRUDE".to_string()));
|
||||
let _ = app.update(Message::CommandSubmit);
|
||||
assert_eq!(
|
||||
app.tabs[0].active_cmd.as_ref().map(|c| c.name()),
|
||||
Some("EXTRUDE")
|
||||
);
|
||||
|
||||
// Pick the rectangle: the GUI route is an entity pick at a world point.
|
||||
let _ = app.feed_command(crate::command::StepInput::EntityPick(
|
||||
handle,
|
||||
glam::DVec3::new(-10.0, -10.0, 0.0),
|
||||
));
|
||||
// Bare Enter finishes selection → Height step (DYN input is on by
|
||||
// default, so the prompt shows a Distance field).
|
||||
let _ = app.update(Message::CommandFinalize);
|
||||
assert_eq!(
|
||||
app.tabs[0].active_cmd.as_ref().map(|c| c.name()),
|
||||
Some("EXTRUDE")
|
||||
);
|
||||
assert!(
|
||||
app.dyn_input
|
||||
&& app.tabs[0]
|
||||
.dyn_fields
|
||||
.iter()
|
||||
.any(|f| f.role == crate::command::DynRole::Distance)
|
||||
);
|
||||
|
||||
// The unfocused-input route for digits while dyn fields show:
|
||||
// CommandAppendChar fills the Distance field buffer, not the
|
||||
// command-line input.
|
||||
for ch in ["5"] {
|
||||
let _ = app.update(Message::CommandAppendChar(ch.to_string()));
|
||||
}
|
||||
assert_eq!(app.command_line.input, "");
|
||||
assert!(
|
||||
app.tabs[0]
|
||||
.dyn_fields
|
||||
.iter()
|
||||
.any(|f| f.buffer.as_deref() == Some("5"))
|
||||
);
|
||||
|
||||
// Enter commits the typed height through the dyn-field buffer.
|
||||
let _ = app.update(Message::CommandFinalize);
|
||||
let solid_count = app.tabs[0]
|
||||
.scene
|
||||
.document
|
||||
.entities()
|
||||
.filter(|e| matches!(e, acadrust::EntityType::Solid3D(_)))
|
||||
.count();
|
||||
assert!(solid_count > 0, "typed height must extrude");
|
||||
assert!(
|
||||
app.tabs[0].active_cmd.is_none(),
|
||||
"EXTRUDE must finish after the typed height"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -472,6 +472,16 @@ impl CadCommand for ExtrudeCommand {
|
||||
fn dyn_live_value(&self, cursor: DVec3) -> Option<f64> {
|
||||
Some((cursor - self.anchor).dot(self.profile_direction?))
|
||||
}
|
||||
// The Height step's dynamic box is a span along the profile normal, not a
|
||||
// point in the drawing plane. Without this, a typed value committed from
|
||||
// the box (the only route on web, where the canvas — not the command
|
||||
// line — holds keyboard focus) is resolved into an in-plane point whose
|
||||
// height projects to ~0 and is silently dropped. `on_text_input` parses
|
||||
// the same string the command-line path would (keywords and
|
||||
// `parse_typed_length`), so both entry routes behave identically (#1082).
|
||||
fn dyn_commit_as_text(&self) -> bool {
|
||||
self.step == ExtrudeStep::Height
|
||||
}
|
||||
fn is_selection_gathering(&self) -> bool {
|
||||
self.step == ExtrudeStep::Pick
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user