Text: duplicate during a text edit leaves no effect selected on the original (#2226)

Duplicate passes over the property selection an open edit kept and copies the edited layer,
but left that selection in place on the original. With the copy selected, the next Duplicate
copied the original's effect, shape item or text animator, and Clear would have removed it.
Ending the edit through Duplicate now clears that property selection along with it.
This commit is contained in:
Christopher Linnett committed 2026-10-28 00:26:52 +08:00
1 parent 9928f6181b
commit eeedd6b540
2 files changed
+13 -2

No files matched your search

+7 -1
View File
@@ -105,10 +105,11 @@ pub(crate) fn reid(layer: &mut Layer, next: &mut u64) {
}
fn duplicate(s: &mut Session, p: &Value) -> Result<Value> {
let editing = s.state.text_edit.is_some();
// Effects selected → duplicate them (Edit ▸ Duplicate in Effect Controls). An open text edit
// comes first, as it does for Clear: opening the editor keeps the property selection, but
// while typing, Duplicate means the edited layer, not an effect or item selected before.
if p.get("layers").is_none() && s.state.text_edit.is_none() {
if p.get("layers").is_none() && !editing {
let fx = super::effect::selected_effects(s);
if !fx.is_empty() {
let mut out = vec![];
@@ -151,6 +152,11 @@ fn duplicate(s: &mut Session, p: &Value) -> Result<Value> {
relink_copies(comp, &map);
proj.next_id = next;
st.selected_layers = created.clone();
// The property selection the edit kept was passed over above and belongs to the
// originals: left in place, the next Duplicate or Clear would act on it, not the copies.
if editing {
st.selected_props.clear();
}
Ok(created)
})?;
Ok(json!(new.iter().map(|l| l.0).collect::<Vec<_>>()))
+6 -1
View File
@@ -1265,11 +1265,16 @@ fn duplicate_during_an_edit_copies_the_layer_not_a_selected_property_group() {
assert_eq!(items(&s).len(), n, "{what}: the selected {what} is not duplicated");
assert_eq!(layers(&s), before + 1, "{what}: the edited layer is");
assert_eq!(s.state.selected_layers, vec![LayerId(r[0].as_u64().unwrap())], "{what}: and its copy is selected");
// The selection the edit passed over goes with it: the next Duplicate copies the selected
// copy rather than reaching back to the original's {what}.
s.execute("edit.duplicate", json!({})).unwrap();
assert_eq!(items(&s).len(), n, "{what}: a second Duplicate leaves the original's {what} alone");
assert_eq!(layers(&s), before + 2, "{what}: and copies the copy");
// With no edit open, the selected item keeps its precedence over the layers.
s.execute("prop.select", json!({"layer": owner, "prop": item})).unwrap();
s.execute("edit.duplicate", json!({})).unwrap();
assert_eq!(items(&s).len(), n + 1, "{what}: outside an edit Duplicate copies the selected {what}");
assert_eq!(layers(&s), before + 1, "{what}: and no layer");
assert_eq!(layers(&s), before + 2, "{what}: and no layer");
}
}