duplicateSubtree static method
DuplicateSceneSubtreeResult
duplicateSubtree(
- CanvasSceneDocument doc,
- NodeId id, {
- Vec2 shift = const Vec2(16, 16),
- IdGenerator? idGen,
Implementation
static DuplicateSceneSubtreeResult duplicateSubtree(
CanvasSceneDocument doc,
NodeId id, {
Vec2 shift = const Vec2(16, 16),
IdGenerator? idGen,
}) {
final node = findById(doc, id);
if (node == null) {
return (doc: doc, idMap: const {}, createdIds: const [], primaryId: null);
}
final pr = findParentOf(doc, id);
if (pr == null) {
return (doc: doc, idMap: const {}, createdIds: const [], primaryId: null);
}
final gen = idGen ?? _defaultIdGen();
final created = <NodeId>[];
final idMap = <NodeId, NodeId>{};
Node clone(Node n) {
final newId = gen(n.id);
idMap[n.id] = newId;
created.add(newId);
final kids = n.childrenOrEmpty;
final clonedKids = kids.isEmpty
? const <Node>[]
: [for (final c in kids) clone(c)];
return n.withId(newId).withChildren(clonedKids);
}
// Clone subtree.
var cloned = clone(node);
// Shift root position only.
final xf0 = cloned.xf;
cloned = cloned.withXf(xf0.copyWith(position: xf0.position + shift));
// Insert immediately after original.
// Later siblings paint above earlier siblings, so the duplicate appears above.
final insertIndex = pr.index + 1;
CanvasSceneDocument out;
if (pr.parent == null) {
final kids = [...doc.children];
kids.insert(_clampInsertIndex(insertIndex, kids.length), cloned);
out = doc.copyWith(children: kids);
} else {
final kids = [...pr.parent!.childrenOrEmpty];
kids.insert(_clampInsertIndex(insertIndex, kids.length), cloned);
out = _replaceChildren(doc, pr.parent, kids);
}
return (doc: out, idMap: idMap, createdIds: created, primaryId: cloned.id);
}