duplicateSubtree static method
DuplicateSceneSubtreeResult
duplicateSubtree(
- CanvasSceneDocument doc,
- ElementId id, {
- Vec2 shift = const Vec2(16, 16),
- IdGenerator? idGen,
Implementation
static DuplicateSceneSubtreeResult duplicateSubtree(
CanvasSceneDocument doc,
ElementId 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 = <ElementId>[];
final idMap = <ElementId, ElementId>{};
Node clone(Node n) {
final newId = gen(n.id);
idMap[n.id] = newId;
created.add(newId);
return switch (n) {
final TextNode node => node.copyWith(id: newId),
final ImageNode node => node.copyWith(id: newId),
final PathNode node => node.copyWith(id: newId),
final IconNode node => node.copyWith(id: newId),
final GroupNode node => node.copyWith(
id: newId,
children: [for (final child in node.children) clone(child)],
),
};
}
// 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);
}