restore method
Write state back into this document — the undo door's other half.
Nodes are REVIVED, not replaced: a live node with the snapshot's name
and kind gets the state copied into it and keeps its object identity,
so fx writers (an Effect, a bound motion), widget keys and anything
else holding the node keep working across an undo. Only nodes the
snapshot has and the document lost come back as fresh copies.
Implementation
void restore(SceneSnapshot state) {
edit(() {
params
..clear()
..addAll(state._params);
var live = {for (var (n, _) in walk()) n.name: n};
SceneNode revive(SceneNode snap) {
var into = live[snap.name];
if (into == null ||
into.runtimeType != snap.runtimeType ||
(into is KindNode && into.kind != (snap as KindNode).kind) ||
(into is ExternalNode &&
into.entry != (snap as ExternalNode).entry) ||
(into is SceneRefNode &&
into.sceneClassName != (snap as SceneRefNode).sceneClassName)) {
return deepCopyNode(snap);
}
switch ((into, snap)) {
case (FrameNode i, FrameNode s):
i
..repeated = s.repeated
..children.clear()
..children.addAll([for (var c in s.children) revive(c)]);
case (ExternalNode i, ExternalNode s):
i
..declared = s.declared
..builder = s.builder
..args.clear();
i.args.addAll(s.args);
case (SceneRefNode i, SceneRefNode s):
i
..declared = s.declared
..tokensArg = s.tokensArg
..args.clear();
i.args.addAll(s.args);
case (KindNode i, KindNode s):
i.children
..clear()
..addAll([for (var c in s.children) revive(c)]);
case (TextNode(), TextNode()) || (ShapeNode(), ShapeNode()):
break;
default:
throw StateError('unreachable: kinds matched above');
}
for (var p in scenePropsOf(snap)) {
p.write(into, p.read(snap));
}
into.bindings
..clear()
..addAll(snap.bindings);
return into;
}
revive(state._root);
// A node the snapshot brought back is a NEW object, and a repeat's
// closure reads the cells of the one it was built for. Rebound here
// rather than left to whoever notices.
bindRepeats(this);
});
}