forked from 1b-agent/opencadstudio-upstream
Keep the task a dispatched command returns
CmdResult::Dispatch and CmdResult::Relaunch end the active command and run the assembled line through dispatch_command, then discarded the Task it returned (`let _ =`). A command whose effect is a message carried by that Task was announced but never applied. VSCURRENT's keyword picker is one: choosing "Gouraud Shaded" printed "Visual style: Gouraud Shaded." and left the drawing in wireframe, because SetRenderMode travels in that Task. Hold the Task and batch it with the focus task that apply_cmd_result_inner returns. A regression test drives both results through VSCURRENT and checks the tab's render mode.
This commit is contained in:
1 parent
768ce2ca82
commit
cf004107b2
1 file changed
+53
-12
+53
-12
@@ -1849,6 +1849,9 @@ impl OpenCADStudio {
|
|||||||
.active_cmd
|
.active_cmd
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_some_and(|command| command.preserve_commit_layer());
|
.is_some_and(|command| command.preserve_commit_layer());
|
||||||
|
// Task produced by a command the arm dispatches; it must reach the
|
||||||
|
// runtime or messages such as a chosen render mode are dropped.
|
||||||
|
let mut dispatched = Task::none();
|
||||||
match result {
|
match result {
|
||||||
CmdResult::OpenAutoConstrainSettings => {
|
CmdResult::OpenAutoConstrainSettings => {
|
||||||
self.auto_constrain_saved = Some(self.auto_constrain_settings.clone());
|
self.auto_constrain_saved = Some(self.auto_constrain_settings.clone());
|
||||||
@@ -4754,7 +4757,7 @@ impl OpenCADStudio {
|
|||||||
self.tabs[i].snap_result = None;
|
self.tabs[i].snap_result = None;
|
||||||
self.tabs[i].scene.clear_preview_wire();
|
self.tabs[i].scene.clear_preview_wire();
|
||||||
self.restore_pre_cmd_tangent();
|
self.restore_pre_cmd_tangent();
|
||||||
let _ = self.dispatch_command(&cmd);
|
dispatched = self.dispatch_command(&cmd);
|
||||||
}
|
}
|
||||||
CmdResult::Dispatch(cmd) => {
|
CmdResult::Dispatch(cmd) => {
|
||||||
// End this interactive front-end, then run the assembled command
|
// End this interactive front-end, then run the assembled command
|
||||||
@@ -4763,7 +4766,7 @@ impl OpenCADStudio {
|
|||||||
self.tabs[i].snap_result = None;
|
self.tabs[i].snap_result = None;
|
||||||
self.tabs[i].scene.clear_preview_wire();
|
self.tabs[i].scene.clear_preview_wire();
|
||||||
self.restore_pre_cmd_tangent();
|
self.restore_pre_cmd_tangent();
|
||||||
let _ = self.dispatch_command(&cmd);
|
dispatched = self.dispatch_command(&cmd);
|
||||||
}
|
}
|
||||||
CmdResult::EditTableCell { handle, point } => {
|
CmdResult::EditTableCell { handle, point } => {
|
||||||
// TABLEDIT's pick: end the pick phase and hand (table, point)
|
// TABLEDIT's pick: end the pick phase and hand (table, point)
|
||||||
@@ -7494,16 +7497,15 @@ impl OpenCADStudio {
|
|||||||
// The rich text canvas owns keyboard editing itself. Leaving the
|
// The rich text canvas owns keyboard editing itself. Leaving the
|
||||||
// hidden command input focused would make it consume Left/Right before
|
// hidden command input focused would make it consume Left/Right before
|
||||||
// the editor can handle them.
|
// the editor can handle them.
|
||||||
if self.mtext_editor.is_some() {
|
let focus = if self.mtext_editor.is_some() {
|
||||||
return self.unfocus_widgets();
|
self.unfocus_widgets()
|
||||||
}
|
} else if self.text_inline.is_some() {
|
||||||
// The in-place TEXT editor needs keyboard focus on its own field.
|
// The in-place TEXT editor needs keyboard focus on its own field.
|
||||||
if self.text_inline.is_some() {
|
iced::widget::operation::focus(iced::widget::Id::new(super::view::TEXT_INLINE_ID))
|
||||||
return iced::widget::operation::focus(iced::widget::Id::new(
|
} else {
|
||||||
super::view::TEXT_INLINE_ID,
|
self.focus_cmd_input()
|
||||||
));
|
};
|
||||||
}
|
Task::batch([dispatched, focus])
|
||||||
self.focus_cmd_input()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Restore the tangent-snap / ortho state that was in effect before the command started.
|
/// Restore the tangent-snap / ortho state that was in effect before the command started.
|
||||||
@@ -10101,3 +10103,42 @@ mod thicken_tests {
|
|||||||
assert!(app.tabs[i].scene.document.get_entity(source).is_some());
|
assert!(app.tabs[i].scene.document.get_entity(source).is_some());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod dispatched_command_task_tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::command::CmdResult;
|
||||||
|
use acadrust::entities::ViewportRenderMode as Mode;
|
||||||
|
|
||||||
|
/// `CmdResult::Dispatch` and `CmdResult::Relaunch` run the assembled line
|
||||||
|
/// through `dispatch_command`, and the Task it returns must reach the
|
||||||
|
/// runtime: the render mode a VSCURRENT keyword picker chooses is applied
|
||||||
|
/// by a message that Task carries.
|
||||||
|
#[test]
|
||||||
|
fn dispatch_and_relaunch_keep_the_task_the_command_returns() {
|
||||||
|
let mut app = OpenCADStudio::new_for_test();
|
||||||
|
let _ = app.automation_op(r#"{"op":"new"}"#);
|
||||||
|
let i = app.active_tab;
|
||||||
|
|
||||||
|
app.tabs[i].render_mode = Mode::Wireframe2D;
|
||||||
|
let task = app.apply_cmd_result(CmdResult::Dispatch("VSCURRENT GOURAUDSHADED".into()));
|
||||||
|
app.drive_headless_task(task).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
app.tabs[i].render_mode,
|
||||||
|
Mode::GouraudShaded,
|
||||||
|
"Dispatch dropped the dispatched command's task"
|
||||||
|
);
|
||||||
|
|
||||||
|
app.tabs[i].render_mode = Mode::Wireframe2D;
|
||||||
|
let task = app.apply_cmd_result(CmdResult::Relaunch(
|
||||||
|
"VSCURRENT GOURAUDSHADED".into(),
|
||||||
|
Vec::new(),
|
||||||
|
));
|
||||||
|
app.drive_headless_task(task).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
app.tabs[i].render_mode,
|
||||||
|
Mode::GouraudShaded,
|
||||||
|
"Relaunch dropped the dispatched command's task"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user