DuplicateFolder_Change.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. using System.Collections.Immutable;
  2. using System.Collections.ObjectModel;
  3. using Drawie.Numerics;
  4. using PixiEditor.ChangeableDocument.Changeables.Animations;
  5. using PixiEditor.ChangeableDocument.Changeables.Graph;
  6. using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
  7. using PixiEditor.ChangeableDocument.ChangeInfos.NodeGraph;
  8. using PixiEditor.ChangeableDocument.ChangeInfos.Structure;
  9. using PixiEditor.ChangeableDocument.Changes.NodeGraph;
  10. namespace PixiEditor.ChangeableDocument.Changes.Structure;
  11. internal class DuplicateFolder_Change : Change
  12. {
  13. private readonly Guid folderGuid;
  14. private Guid duplicateGuid;
  15. private Guid[] contentGuids;
  16. private Guid[] contentDuplicateGuids;
  17. private Guid[]? childGuidsToUse;
  18. private Dictionary<Guid, List<Guid>> keyFramesMap = new();
  19. private Dictionary<Guid, Guid> nodeMap = new();
  20. private ConnectionsData? connectionsData;
  21. private Dictionary<Guid, ConnectionsData> contentConnectionsData = new();
  22. private Dictionary<Guid, VecD> originalPositions;
  23. [GenerateMakeChangeAction]
  24. public DuplicateFolder_Change(Guid folderGuid, Guid newGuid, ImmutableList<Guid>? childGuids)
  25. {
  26. this.folderGuid = folderGuid;
  27. duplicateGuid = newGuid;
  28. childGuidsToUse = childGuids?.ToArray();
  29. }
  30. public override bool InitializeAndValidate(Document target)
  31. {
  32. if (!target.TryFindMember<FolderNode>(folderGuid, out FolderNode? folder))
  33. return false;
  34. connectionsData = NodeOperations.CreateConnectionsData(folder);
  35. List<Guid> contentGuidList = new();
  36. folder.Content.Connection?.Node.TraverseBackwards(x =>
  37. {
  38. contentGuidList.Add(x.Id);
  39. contentConnectionsData[x.Id] = NodeOperations.CreateConnectionsData(x);
  40. return true;
  41. });
  42. return true;
  43. }
  44. public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, bool firstApply,
  45. out bool ignoreInUndo)
  46. {
  47. (FolderNode existingLayer, Node parent) = ((FolderNode, Node))target.FindChildAndParentOrThrow(folderGuid);
  48. FolderNode clone = (FolderNode)existingLayer.Clone();
  49. clone.Id = duplicateGuid;
  50. InputProperty<Painter?> targetInput = parent.InputProperties.FirstOrDefault(x =>
  51. x.ValueType == typeof(Painter) &&
  52. x.Connection is { Node: StructureNode }) as InputProperty<Painter?>;
  53. List<IChangeInfo> operations = new();
  54. target.NodeGraph.AddNode(clone);
  55. var previousConnection = targetInput.Connection;
  56. operations.Add(CreateNode_ChangeInfo.CreateFromNode(clone));
  57. operations.AddRange(NodeOperations.AppendMember(targetInput, clone.Output, clone.Background, clone.Id));
  58. operations.AddRange(NodeOperations.AdjustPositionsAfterAppend(clone, targetInput.Node,
  59. previousConnection?.Node as Node, out originalPositions));
  60. DuplicateContent(target, clone, existingLayer, operations, firstApply);
  61. ignoreInUndo = false;
  62. return operations;
  63. }
  64. public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
  65. {
  66. var (member, parent) = target.FindChildAndParentOrThrow(duplicateGuid);
  67. target.NodeGraph.RemoveNode(member);
  68. member.Dispose();
  69. List<IChangeInfo> changes = new();
  70. changes.AddRange(NodeOperations.DetachStructureNode(member));
  71. changes.Add(new DeleteStructureMember_ChangeInfo(member.Id));
  72. if (contentDuplicateGuids is not null)
  73. {
  74. foreach (Guid contentGuid in contentDuplicateGuids)
  75. {
  76. Node contentNode = target.FindNodeOrThrow<Node>(contentGuid);
  77. changes.AddRange(NodeOperations.DetachNode(target.NodeGraph, contentNode));
  78. changes.Add(new DeleteNode_ChangeInfo(contentNode.Id));
  79. target.NodeGraph.RemoveNode(contentNode);
  80. contentNode.Dispose();
  81. }
  82. }
  83. if (connectionsData is not null)
  84. {
  85. Node originalNode = target.FindNodeOrThrow<Node>(folderGuid);
  86. changes.AddRange(
  87. NodeOperations.ConnectStructureNodeProperties(connectionsData, originalNode, target.NodeGraph));
  88. }
  89. changes.AddRange(NodeOperations.RevertPositions(originalPositions, target));
  90. return changes;
  91. }
  92. private void DuplicateContent(Document target, FolderNode clone, FolderNode existingLayer,
  93. List<IChangeInfo> operations, bool firstApply)
  94. {
  95. if (firstApply)
  96. {
  97. nodeMap = new Dictionary<Guid, Guid>();
  98. nodeMap[existingLayer.Id] = clone.Id;
  99. }
  100. int counter = 0;
  101. List<Guid> contentGuidList = new();
  102. if (firstApply)
  103. {
  104. keyFramesMap = new Dictionary<Guid, List<Guid>>();
  105. }
  106. int childCounter = 0;
  107. existingLayer.Content.Connection?.Node.TraverseBackwards(x =>
  108. {
  109. if (x is not Node targetNode)
  110. return false;
  111. Node? node = targetNode.Clone();
  112. if (contentDuplicateGuids != null && contentDuplicateGuids.Length > 0)
  113. {
  114. node.Id = contentDuplicateGuids[childCounter];
  115. childCounter++;
  116. }
  117. else
  118. {
  119. if (node is not FolderNode && childGuidsToUse is not null && counter < childGuidsToUse.Length)
  120. {
  121. node.Id = childGuidsToUse[counter];
  122. counter++;
  123. }
  124. }
  125. if (firstApply)
  126. {
  127. keyFramesMap[node.Id] = new List<Guid>();
  128. keyFramesMap[node.Id].AddRange(x.KeyFrames.Select(kf => kf.KeyFrameGuid));
  129. }
  130. else
  131. {
  132. if (keyFramesMap.TryGetValue(node.Id, out List<Guid>? keyFrameGuids))
  133. {
  134. for (int i = 0; i < x.KeyFrames.Count; i++)
  135. {
  136. if (i < keyFrameGuids.Count)
  137. {
  138. var kf = x.KeyFrames[i] as KeyFrameData;
  139. kf.KeyFrameGuid = keyFrameGuids[i];
  140. }
  141. }
  142. }
  143. }
  144. if (firstApply)
  145. {
  146. nodeMap[x.Id] = node.Id;
  147. contentGuidList.Add(node.Id);
  148. }
  149. target.NodeGraph.AddNode(node);
  150. operations.Add(CreateNode_ChangeInfo.CreateFromNode(node));
  151. return true;
  152. });
  153. foreach (var data in contentConnectionsData)
  154. {
  155. var updatedData = data.Value.WithUpdatedIds(nodeMap);
  156. Guid targetNodeId = nodeMap[data.Key];
  157. operations.AddRange(NodeOperations.ConnectStructureNodeProperties(updatedData,
  158. target.FindNodeOrThrow<Node>(targetNodeId), target.NodeGraph));
  159. }
  160. if (firstApply)
  161. {
  162. contentDuplicateGuids = contentGuidList.ToArray();
  163. }
  164. }
  165. }