Browse Source

Duplication connections

flabbet 7 months ago
parent
commit
1a35be8faf

+ 2 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CreateImageNode.cs

@@ -66,6 +66,8 @@ public class CreateImageNode : Node, IPreviewRenderable
 
 
     private void OnPaint(RenderContext context, DrawingSurface surface)
     private void OnPaint(RenderContext context, DrawingSurface surface)
     {
     {
+        if(Output.Value == null || Output.Value.IsDisposed) return;
+        
         surface.Canvas.DrawSurface(Output.Value.DrawingSurface, 0, 0);
         surface.Canvas.DrawSurface(Output.Value.DrawingSurface, 0, 0);
     }
     }
 
 

+ 3 - 3
src/PixiEditor.ChangeableDocument/Changes/NodeGraph/DuplicateNode_Change.cs

@@ -10,9 +10,10 @@ internal class DuplicateNode_Change : Change
     private Guid createdNodeGuid;
     private Guid createdNodeGuid;
 
 
     [GenerateMakeChangeAction]
     [GenerateMakeChangeAction]
-    public DuplicateNode_Change(Guid nodeGuid)
+    public DuplicateNode_Change(Guid nodeGuid, Guid newGuid)
     {
     {
         this.nodeGuid = nodeGuid;
         this.nodeGuid = nodeGuid;
+        createdNodeGuid = newGuid;
     }
     }
 
 
     public override bool InitializeAndValidate(Document target)
     public override bool InitializeAndValidate(Document target)
@@ -25,8 +26,7 @@ internal class DuplicateNode_Change : Change
     {
     {
         Node existingNode = target.FindNode(nodeGuid);
         Node existingNode = target.FindNode(nodeGuid);
         Node clone = existingNode.Clone();
         Node clone = existingNode.Clone();
-        
-        createdNodeGuid = clone.Id;
+        clone.Id = createdNodeGuid;
 
 
         target.NodeGraph.AddNode(clone);
         target.NodeGraph.AddNode(clone);
 
 

+ 3 - 6
src/PixiEditor/Models/Controllers/ClipboardController.cs

@@ -585,15 +585,12 @@ internal static class ClipboardController
         await Clipboard.SetDataObjectAsync(data);
         await Clipboard.SetDataObjectAsync(data);
     }
     }
 
 
-    public static async Task PasteNodes(DocumentViewModel document)
+    public static async Task<List<Guid>> GetNodeIds()
     {
     {
         var data = await TryGetDataObject();
         var data = await TryGetDataObject();
         var nodeIds = GetNodeIds(data);
         var nodeIds = GetNodeIds(data);
-
-        foreach (var nodeId in nodeIds)
-        {
-            document.Operations.DuplicateNode(nodeId);
-        }
+        
+        return nodeIds.ToList();
     }
     }
 
 
     public static async Task<Guid[]> GetNodesFromClipboard()
     public static async Task<Guid[]> GetNodesFromClipboard()

+ 10 - 3
src/PixiEditor/Models/DocumentModels/Public/DocumentOperationsModule.cs

@@ -838,13 +838,20 @@ internal class DocumentOperationsModule : IDocumentOperations
             new ChangeProcessingColorSpace_Action(ColorSpace.CreateSrgb()));
             new ChangeProcessingColorSpace_Action(ColorSpace.CreateSrgb()));
     }
     }
 
 
-    public void DuplicateNode(Guid nodeId)
+    public Guid? DuplicateNode(Guid nodeId)
     {
     {
         if (Internals.ChangeController.IsBlockingChangeActive)
         if (Internals.ChangeController.IsBlockingChangeActive)
-            return;
+            return null;
 
 
         Internals.ChangeController.TryStopActiveExecutor();
         Internals.ChangeController.TryStopActiveExecutor();
+        
+        if(!Document.StructureHelper.TryFindNode(nodeId, out INodeHandler node) || node.InternalName == OutputNode.UniqueName)
+            return null;
 
 
-        Internals.ActionAccumulator.AddFinishedActions(new DuplicateNode_Action(nodeId));
+        Guid newGuid = Guid.NewGuid();
+        
+        Internals.ActionAccumulator.AddFinishedActions(new DuplicateNode_Action(nodeId, newGuid));
+        
+        return newGuid;
     }
     }
 }
 }

+ 6 - 1
src/PixiEditor/Models/DocumentModels/Public/DocumentStructureModule.cs

@@ -26,6 +26,11 @@ internal class DocumentStructureModule
         return doc.NodeGraphHandler.AllNodes.FirstOrDefault(x => x.Id == guid && x is T) as T;
         return doc.NodeGraphHandler.AllNodes.FirstOrDefault(x => x.Id == guid && x is T) as T;
     }
     }
 
 
+    public bool TryFindNode<T>(Guid guid, out T found) where T : class, INodeHandler
+    {
+        found = FindNode<T>(guid);
+        return found != null;
+    }
 
 
     public Guid FindClosestMember(IReadOnlyList<Guid> guids)
     public Guid FindClosestMember(IReadOnlyList<Guid> guids)
     {
     {
@@ -140,7 +145,7 @@ internal class DocumentStructureModule
 
 
         return layers;
         return layers;
     }
     }
-    
+
     public List<IStructureMemberHandler> GetAllMembers()
     public List<IStructureMemberHandler> GetAllMembers()
     {
     {
         List<IStructureMemberHandler> members = new List<IStructureMemberHandler>();
         List<IStructureMemberHandler> members = new List<IStructureMemberHandler>();

+ 71 - 6
src/PixiEditor/ViewModels/SubViewModels/ClipboardViewModel.cs

@@ -20,6 +20,7 @@ using PixiEditor.Models.Layers;
 using Drawie.Numerics;
 using Drawie.Numerics;
 using PixiEditor.UI.Common.Fonts;
 using PixiEditor.UI.Common.Fonts;
 using PixiEditor.ViewModels.Dock;
 using PixiEditor.ViewModels.Dock;
+using PixiEditor.ViewModels.Document;
 
 
 namespace PixiEditor.ViewModels.SubViewModels;
 namespace PixiEditor.ViewModels.SubViewModels;
 #nullable enable
 #nullable enable
@@ -146,7 +147,7 @@ internal class ClipboardViewModel : SubViewModel<ViewModelMain>
             Owner.ColorsSubViewModel.SecondaryColor = result.Value;
             Owner.ColorsSubViewModel.SecondaryColor = result.Value;
         }
         }
     }
     }
-    
+
     [Command.Basic("PixiEditor.Clipboard.PasteNodes", "PASTE_NODES", "PASTE_NODES_DESCRIPTIVE",
     [Command.Basic("PixiEditor.Clipboard.PasteNodes", "PASTE_NODES", "PASTE_NODES_DESCRIPTIVE",
         ShortcutContexts = [typeof(NodeGraphDockViewModel)], Key = Key.V, Modifiers = KeyModifiers.Control,
         ShortcutContexts = [typeof(NodeGraphDockViewModel)], Key = Key.V, Modifiers = KeyModifiers.Control,
         CanExecute = "PixiEditor.Clipboard.CanPasteNodes", Icon = PixiPerfectIcons.Paste, AnalyticsTrack = true)]
         CanExecute = "PixiEditor.Clipboard.CanPasteNodes", Icon = PixiPerfectIcons.Paste, AnalyticsTrack = true)]
@@ -156,9 +157,45 @@ internal class ClipboardViewModel : SubViewModel<ViewModelMain>
         if (doc is null)
         if (doc is null)
             return;
             return;
 
 
-        await ClipboardController.PasteNodes(doc);
+        List<Guid> toDuplicate = await ClipboardController.GetNodeIds();
+
+        List<Guid> newIds = new();
+
+        Dictionary<Guid, Guid> nodeMapping = new();
+
+        foreach (var nodeId in toDuplicate)
+        {
+            Guid? newId = doc.Operations.DuplicateNode(nodeId);
+            if (newId != null)
+            {
+                newIds.Add(newId.Value);
+                nodeMapping.Add(nodeId, newId.Value);
+            }
+        }
+
+        if (newIds.Count == 0)
+            return;
+        
+        doc.Operations.InvokeCustomAction(() =>
+        {
+            ConnectRelatedNodes(doc, nodeMapping);
+            foreach (var node in doc.NodeGraph.AllNodes)
+            {
+                node.IsNodeSelected = false;
+            }
+
+            foreach (var node in newIds)
+            {
+                var nodeInstance = doc.NodeGraph.AllNodes.FirstOrDefault(x => x.Id == node);
+                if (nodeInstance != null)
+                {
+                    nodeInstance.IsNodeSelected = true;
+                }
+            }
+        });
     }
     }
 
 
+
     [Command.Basic("PixiEditor.Clipboard.Copy", "COPY", "COPY_DESCRIPTIVE", CanExecute = "PixiEditor.Clipboard.CanCopy",
     [Command.Basic("PixiEditor.Clipboard.Copy", "COPY", "COPY_DESCRIPTIVE", CanExecute = "PixiEditor.Clipboard.CanCopy",
         Key = Key.C, Modifiers = KeyModifiers.Control,
         Key = Key.C, Modifiers = KeyModifiers.Control,
         ShortcutContexts = [typeof(ViewportWindowViewModel), typeof(LayersDockViewModel)],
         ShortcutContexts = [typeof(ViewportWindowViewModel), typeof(LayersDockViewModel)],
@@ -198,11 +235,11 @@ internal class ClipboardViewModel : SubViewModel<ViewModelMain>
         var selectedNodes = doc.NodeGraph.AllNodes.Where(x => x.IsNodeSelected).Select(x => x.Id).ToArray();
         var selectedNodes = doc.NodeGraph.AllNodes.Where(x => x.IsNodeSelected).Select(x => x.Id).ToArray();
         if (selectedNodes.Length == 0)
         if (selectedNodes.Length == 0)
             return;
             return;
-        
+
         await ClipboardController.CopyNodes(selectedNodes);
         await ClipboardController.CopyNodes(selectedNodes);
     }
     }
-    
-    
+
+
     [Command.Basic("PixiEditor.Clipboard.CopyPrimaryColorAsHex", CopyColor.PrimaryHEX, "COPY_COLOR_HEX",
     [Command.Basic("PixiEditor.Clipboard.CopyPrimaryColorAsHex", CopyColor.PrimaryHEX, "COPY_COLOR_HEX",
         "COPY_COLOR_HEX_DESCRIPTIVE", IconEvaluator = "PixiEditor.Clipboard.CopyColorIcon", AnalyticsTrack = true)]
         "COPY_COLOR_HEX_DESCRIPTIVE", IconEvaluator = "PixiEditor.Clipboard.CopyColorIcon", AnalyticsTrack = true)]
     [Command.Basic("PixiEditor.Clipboard.CopyPrimaryColorAsRgb", CopyColor.PrimaryRGB, "COPY_COLOR_RGB",
     [Command.Basic("PixiEditor.Clipboard.CopyPrimaryColorAsRgb", CopyColor.PrimaryRGB, "COPY_COLOR_RGB",
@@ -243,7 +280,7 @@ internal class ClipboardViewModel : SubViewModel<ViewModelMain>
             ? ClipboardController.IsImage(data)
             ? ClipboardController.IsImage(data)
             : ClipboardController.IsImageInClipboard().Result;
             : ClipboardController.IsImageInClipboard().Result;
     }
     }
-    
+
     [Evaluator.CanExecute("PixiEditor.Clipboard.CanPasteNodes")]
     [Evaluator.CanExecute("PixiEditor.Clipboard.CanPasteNodes")]
     public bool CanPasteNodes()
     public bool CanPasteNodes()
     {
     {
@@ -304,6 +341,34 @@ internal class ClipboardViewModel : SubViewModel<ViewModelMain>
         return ColorSearchResult.GetIcon(targetColor.ToOpaqueMediaColor().ToOpaqueColor());
         return ColorSearchResult.GetIcon(targetColor.ToOpaqueMediaColor().ToOpaqueColor());
     }
     }
 
 
+    private void ConnectRelatedNodes(DocumentViewModel doc, Dictionary<Guid, Guid> nodeMapping)
+    {
+        foreach (var connection in doc.NodeGraph.Connections)
+        {
+            if (nodeMapping.TryGetValue(connection.InputNode.Id, out var inputNode) &&
+                nodeMapping.TryGetValue(connection.OutputNode.Id, out var outputNode))
+            {
+                var inputNodeInstance = doc.NodeGraph.AllNodes.FirstOrDefault(x => x.Id == inputNode);
+                var outputNodeInstance = doc.NodeGraph.AllNodes.FirstOrDefault(x => x.Id == outputNode);
+
+                if (inputNodeInstance == null || outputNodeInstance == null)
+                    continue;
+
+                var inputProperty =
+                    inputNodeInstance.Inputs.FirstOrDefault(
+                        x => x.PropertyName == connection.InputProperty.PropertyName);
+                var outputProperty =
+                    outputNodeInstance.Outputs.FirstOrDefault(x =>
+                        x.PropertyName == connection.OutputProperty.PropertyName);
+
+                if (inputProperty == null || outputProperty == null)
+                    continue;
+
+                doc.NodeGraph.ConnectProperties(inputProperty, outputProperty);
+            }
+        }
+    }
+
     public enum CopyColor
     public enum CopyColor
     {
     {
         PrimaryHEX,
         PrimaryHEX,