Edit: an open text edit stands down the Project-panel Clear redirect (#2227)

Edit > Clear follows panel focus: with the Project panel focused it
redirects to project.delete, which removes the selection at once when
nothing uses it. With a text edit open, that deletes the composition
being typed into — the user is working in it — and undo restores the
item but not the active composition. During a text edit the redirect
stands down (Clear does nothing) and the Edit menu's Clear entry is
disabled, mirroring how Deselect All stands down in #2096.

Co-Authored-By: GLM-5.3-Flash <noreply@z.ai>
This commit is contained in:
SusieeTheFemboyandGLM-5.3-Flash committed 2026-10-29 05:22:56 +01:00
1 parent 990fa668cd
commit 63f1698cff
3 files changed
+34 -2

No files matched your search

+2 -1
View File
@@ -119,7 +119,8 @@ pub(crate) fn entry_enabled(app: &EffectcraftApp, e: &MenuEntry) -> bool {
}
}
if e.command == "edit.clear" && app.ui.focused == PanelKind::Project {
return app.session.is_enabled("project.delete");
// An open text edit stands down: Clear must not delete the comp being typed into (#2227).
return app.session.state.text_edit.is_none() && app.session.is_enabled("project.delete");
}
if e.command == "edit.clear" && app.ui.focused == PanelKind::RenderQueue {
return !app.session.is_rendering() && !app.session.project.render_queue.is_empty();
+6 -1
View File
@@ -223,8 +223,13 @@ pub fn invoke(app: &mut EffectcraftApp, ctx: &egui::Context, id: &str, params: V
return run_engine(app, ctx, "edit.pasteSvg", json!({"svg": svg}));
}
}
// Clear follows panel focus, including the Edit menu and keyboard shortcut.
// Clear follows panel focus, including the Edit menu and keyboard shortcut. An open text
// edit stands down: the user is working in a composition, and the Project-panel redirect
// would delete it without asking when nothing uses it (#2227).
if id == "edit.clear" && params.as_object().is_some_and(|p| p.is_empty()) && app.ui.focused == PanelKind::Project {
if app.session.state.text_edit.is_some() {
return Ok(Value::Null);
}
// Through `invoke`, so deleting items that compositions use still asks first (M3.16).
return invoke(app, ctx, "project.delete", json!({}));
}
@@ -364,3 +364,29 @@ fn a_cut_is_read_with_the_modifiers_where_it_is_in_the_frame() {
assert_eq!(h.state().session.project.item(solid).is_none(), deletes, "case {n}: {events:?} after {before:?}");
}
}
/// An open text edit stands down the Project-panel Clear redirect: the composition being typed
/// into must not be deleted out from under it, with no confirmation when nothing uses it (#2227).
#[test]
fn clear_with_the_project_focused_stands_down_during_a_text_edit() {
let (mut h, _, _) = harness();
let working = h.state().session.active_comp_id().unwrap();
// the composition being typed into is also the Project panel's selection, as when it was opened
click(&mut h, &format!("project.item.{}.name", working.0), Modifiers::NONE);
let text = h.state_mut().session.execute("layer.newText", json!({"text": "Title", "size": 80})).unwrap()["layer"].as_u64().unwrap();
h.state_mut().session.execute("text.edit", json!({"layer": text, "created": true})).unwrap();
h.state_mut().ui.focused = PanelKind::Project;
h.run_steps(2);
assert!(h.state().session.state.project_selection.contains(&working), "the comp is the project selection");
let project = h.state().session.project.clone();
// Edit > Clear (the menu, or the control channel) dispatches through `invoke`
let ctx = h.ctx.clone();
let cleared = effectcraft_ui_egui::menus::invoke(h.state_mut(), &ctx, "edit.clear", json!({}));
h.run_steps(3);
cleared.expect("Clear stands down during a text edit");
assert!(h.state().session.project.item(working).is_some(), "the composition being typed into survives");
assert_eq!(h.state().session.project, project, "nothing was deleted");
assert!(h.state().session.state.text_edit.is_some(), "the text edit stays open");
}