Browse Source

Fixed create layer

flabbet 1 year ago
parent
commit
9c715b4e10

+ 20 - 13
src/PixiEditor.AvaloniaUI/Models/DocumentModels/DocumentStructureHelper.cs

@@ -2,6 +2,7 @@
 using PixiEditor.AvaloniaUI.Models.Handlers;
 using PixiEditor.AvaloniaUI.Models.Layers;
 using PixiEditor.ChangeableDocument.Actions.Generated;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
 using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.Extensions.Common.Localization;
 
@@ -17,16 +18,20 @@ internal class DocumentStructureHelper
         this.internals = internals;
     }
 
-    private string GetUniqueName(string name, IFolderHandler folder)
+    private string GetUniqueName(string name, INodeHandler node)
     {
         int count = 1;
-        //TODO: implement this
-        /*foreach (var child in folder.Children)
+        node.TraverseBackwards(newNode =>
         {
-            string childName = child.NameBindable;
-            if (childName.StartsWith(name))
-                count++;
-        }*/
+            if (newNode is IStructureMemberHandler structureMemberHandler)
+            {
+                string childName = structureMemberHandler.NameBindable;
+                if (childName.StartsWith(name))
+                    count++;
+            }
+            
+            return true;
+        });
         return $"{name} {count}";
     }
 
@@ -37,8 +42,10 @@ internal class DocumentStructureHelper
         {
             Guid guid = Guid.NewGuid();
             //put member on top
-            //internals.ActionAccumulator.AddActions(new CreateStructureMember_Action(doc.StructureRoot.Id, guid, doc.StructureRoot.Children.Count, type));
-            //name ??= GetUniqueName(type == StructureMemberType.Layer ? new LocalizedString("NEW_LAYER") : new LocalizedString("NEW_FOLDER"), doc.StructureRoot);
+            internals.ActionAccumulator.AddActions(new CreateStructureMember_Action(
+                doc.NodeGraphHandler.OutputNode.Id, 
+                guid, type));
+            name ??= GetUniqueName(type == StructureMemberType.Layer ? new LocalizedString("NEW_LAYER") : new LocalizedString("NEW_FOLDER"), doc.NodeGraphHandler.OutputNode);
             internals.ActionAccumulator.AddActions(new StructureMemberName_Action(guid, name));
             if (finish)
                 internals.ActionAccumulator.AddFinishedActions();
@@ -48,7 +55,7 @@ internal class DocumentStructureHelper
         {
             Guid guid = Guid.NewGuid();
             //put member inside folder on top
-            //internals.ActionAccumulator.AddActions(new CreateStructureMember_Action(folder.Id, guid, folder.Children.Count, type));
+            internals.ActionAccumulator.AddActions(new CreateStructureMember_Action(folder.Id, guid, type));
             name ??= GetUniqueName(type == StructureMemberType.Layer ? new LocalizedString("NEW_LAYER") : new LocalizedString("NEW_FOLDER"), folder);
             internals.ActionAccumulator.AddActions(new StructureMemberName_Action(guid, name));
             if (finish)
@@ -60,10 +67,10 @@ internal class DocumentStructureHelper
             Guid guid = Guid.NewGuid();
             //put member above the layer
             List<IStructureMemberHandler> path = doc.StructureHelper.FindPath(layer.Id);
-            if (path.Count < 2)
+            if (path.Count < 1)
                 throw new InvalidOperationException("Couldn't find a path to the selected member");
-            IFolderHandler parent = (IFolderHandler)path[1];
-            //internals.ActionAccumulator.AddActions(new CreateStructureMember_Action(parent.Id, guid, parent.Children.IndexOf(layer) + 1, type));
+            INodeHandler parent = path[0];
+            internals.ActionAccumulator.AddActions(new CreateStructureMember_Action(parent.Id, guid, type));
             name ??= GetUniqueName(type == StructureMemberType.Layer ? new LocalizedString("NEW_LAYER") : new LocalizedString("NEW_FOLDER"), parent);
             internals.ActionAccumulator.AddActions(new StructureMemberName_Action(guid, name));
             if (finish)

+ 5 - 0
src/PixiEditor.AvaloniaUI/Models/Rendering/AffectedAreasGatherer.cs

@@ -8,6 +8,7 @@ using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using PixiEditor.ChangeableDocument.ChangeInfos;
 using PixiEditor.ChangeableDocument.ChangeInfos.Animation;
 using PixiEditor.ChangeableDocument.ChangeInfos.Drawing;
+using PixiEditor.ChangeableDocument.ChangeInfos.NodeGraph;
 using PixiEditor.ChangeableDocument.ChangeInfos.Properties;
 using PixiEditor.ChangeableDocument.ChangeInfos.Root;
 using PixiEditor.ChangeableDocument.ChangeInfos.Structure;
@@ -126,6 +127,10 @@ internal class AffectedAreasGatherer
                     AddWholeCanvasToMainImage();
                     AddWholeCanvasToEveryImagePreview();
                     break;
+                case ConnectProperty_ChangeInfo:
+                    AddWholeCanvasToMainImage();
+                    AddWholeCanvasToEveryImagePreview();
+                    break;
             }
         }
     }

+ 1 - 2
src/PixiEditor.AvaloniaUI/ViewModels/Document/DocumentViewModel.cs

@@ -192,7 +192,6 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
     public ReferenceLayerViewModel ReferenceLayerViewModel { get; }
     public LineToolOverlayViewModel LineToolOverlayViewModel { get; }
     public AnimationDataViewModel AnimationDataViewModel { get; }
-    public NodeGraphManagerViewModel NodeGraphManagerViewModel { get; }
 
     public IReadOnlyCollection<IStructureMemberHandler> SoftSelectedStructureMembers => softSelectedStructureMembers;
     private DocumentInternalParts Internals { get; }
@@ -283,7 +282,7 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
         void AddMember(Guid parentGuid, DocumentViewModelBuilder.StructureMemberBuilder member)
         {
             acc.AddActions(
-                new CreateStructureMember_Action(parentGuid, member.Id, 0,
+                new CreateStructureMember_Action(parentGuid, member.Id,
                     member is DocumentViewModelBuilder.LayerBuilder
                         ? StructureMemberType.Layer
                         : StructureMemberType.Folder),

+ 8 - 1
src/PixiEditor.AvaloniaUI/ViewModels/Document/NodeGraphViewModel.cs

@@ -47,8 +47,13 @@ internal class NodeGraphViewModel : ViewModelBase, INodeGraphHandler
         if (existingInputConnection != null)
         {
             Connections.Remove(existingInputConnection);
+            existingInputConnection.InputProperty.ConnectedOutput = null;
+            existingInputConnection.OutputProperty.ConnectedInputs.Remove(existingInputConnection.InputProperty);
         }
         
+        connection.InputProperty.ConnectedOutput = connection.OutputProperty;
+        connection.OutputProperty.ConnectedInputs.Add(connection.InputProperty);
+        
         Connections.Add(connection);
     }
 
@@ -57,8 +62,10 @@ internal class NodeGraphViewModel : ViewModelBase, INodeGraphHandler
         var connection = Connections.FirstOrDefault(x => x.InputProperty.Node.Id == nodeId && x.InputProperty.PropertyName == property);
         if (connection != null)
         {
+            connection.InputProperty.ConnectedOutput = null;
+            connection.OutputProperty.ConnectedInputs.Remove(connection.InputProperty);
             Connections.Remove(connection);
-        } 
+        }
     }
 
     public bool TryTraverse(Func<INodeHandler, bool> func)

+ 1 - 1
src/PixiEditor.AvaloniaUI/ViewModels/Nodes/NodeViewModel.cs

@@ -120,7 +120,7 @@ internal class NodeViewModel : ObservableObject, INodeHandler
             {
                 if (inputProperty.ConnectedOutput != null)
                 {
-                    queueNodes.Enqueue(inputProperty.Node);
+                    queueNodes.Enqueue(inputProperty.ConnectedOutput.Node);
                 }
             }
         }

+ 2 - 4
src/PixiEditor.ChangeableDocument/ChangeInfos/Structure/CreateFolder_ChangeInfo.cs

@@ -9,7 +9,6 @@ public record class CreateFolder_ChangeInfo : CreateStructureMember_ChangeInfo
 {
     public CreateFolder_ChangeInfo(
         Guid parentGuid,
-        int index,
         float opacity,
         bool isVisible,
         bool clipToMemberBelow,
@@ -20,16 +19,15 @@ public record class CreateFolder_ChangeInfo : CreateStructureMember_ChangeInfo
         bool maskIsVisible,
         ImmutableArray<NodePropertyInfo> Inputs,
         ImmutableArray<NodePropertyInfo> Outputs
-    ) : base(parentGuid, index, opacity, isVisible, clipToMemberBelow, name, blendMode, guidValue, hasMask,
+    ) : base(parentGuid, opacity, isVisible, clipToMemberBelow, name, blendMode, guidValue, hasMask,
         maskIsVisible, Inputs, Outputs)
     {
     }
 
-    internal static CreateFolder_ChangeInfo FromFolder(Guid parentGuid, int index, FolderNode folder)
+    internal static CreateFolder_ChangeInfo FromFolder(Guid parentGuid, FolderNode folder)
     {
         return new CreateFolder_ChangeInfo(
             parentGuid,
-            index,
             folder.Opacity.Value,
             folder.IsVisible.Value,
             folder.ClipToMemberBelow.Value,

+ 2 - 4
src/PixiEditor.ChangeableDocument/ChangeInfos/Structure/CreateLayer_ChangeInfo.cs

@@ -11,7 +11,6 @@ public record class CreateLayer_ChangeInfo : CreateStructureMember_ChangeInfo
 {
     public CreateLayer_ChangeInfo(
         Guid parentGuid,
-        int index,
         float opacity,
         bool isVisible,
         bool clipToMemberBelow,
@@ -23,7 +22,7 @@ public record class CreateLayer_ChangeInfo : CreateStructureMember_ChangeInfo
         bool lockTransparency,
         ImmutableArray<NodePropertyInfo> inputs,
         ImmutableArray<NodePropertyInfo> outputs) :
-        base(parentGuid, index, opacity, isVisible, clipToMemberBelow, name, blendMode, guidValue, hasMask,
+        base(parentGuid, opacity, isVisible, clipToMemberBelow, name, blendMode, guidValue, hasMask,
             maskIsVisible, inputs, outputs)
     {
         LockTransparency = lockTransparency;
@@ -31,11 +30,10 @@ public record class CreateLayer_ChangeInfo : CreateStructureMember_ChangeInfo
 
     public bool LockTransparency { get; }
 
-    internal static CreateLayer_ChangeInfo FromLayer(Guid parentGuid, int index, LayerNode layer)
+    internal static CreateLayer_ChangeInfo FromLayer(Guid parentGuid, LayerNode layer)
     {
         return new CreateLayer_ChangeInfo(
             parentGuid,
-            index,
             layer.Opacity.Value,
             layer.IsVisible.Value,
             layer.ClipToMemberBelow.Value,

+ 0 - 1
src/PixiEditor.ChangeableDocument/ChangeInfos/Structure/CreateStructureMember_ChangeInfo.cs

@@ -8,7 +8,6 @@ namespace PixiEditor.ChangeableDocument.ChangeInfos.Structure;
 
 public abstract record class CreateStructureMember_ChangeInfo(
     Guid ParentGuid,
-    int Index,
     float Opacity,
     bool IsVisible,
     bool ClipToMemberBelow,

+ 45 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CircleNode.cs

@@ -0,0 +1,45 @@
+using PixiEditor.ChangeableDocument.Changeables.Animations;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.Numerics;
+
+namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
+
+public class CircleNode : Node
+{
+    public InputProperty<int> Radius { get; }
+    public InputProperty<int> X { get; }
+    public InputProperty<int> Y { get; }
+    public InputProperty<Color> StrokeColor { get; }
+    public InputProperty<Color> FillColor { get; }
+    public InputProperty<int> StrokeWidth { get; }
+    public OutputProperty<ChunkyImage> Output { get; }
+    
+    public CircleNode() 
+    {
+        Radius = CreateInput<int>("Radius", "RADIUS", 10);
+        X = CreateInput<int>("X", "X", 0);
+        Y = CreateInput<int>("Y", "Y", 0);
+        StrokeColor = CreateInput<Color>("StrokeColor", "STROKE_COLOR", new Color(0, 0, 0, 255));
+        FillColor = CreateInput<Color>("FillColor", "FILL_COLOR", new Color(0, 0, 0, 255));
+        StrokeWidth = CreateInput<int>("StrokeWidth", "STROKE_WIDTH", 1);
+        Output = CreateOutput<ChunkyImage>("Output", "OUTPUT", null);
+    }
+    
+    public override ChunkyImage? OnExecute(KeyFrameTime frameTime)
+    {
+        Output.Value = new ChunkyImage(new VecI(Radius.Value * 2, Radius.Value * 2));
+        
+        Output.Value.EnqueueDrawEllipse(
+            RectI.Create(X.Value, Y.Value, Radius.Value * 2, Radius.Value * 2), 
+            FillColor.Value, StrokeColor.Value, StrokeWidth.Value);
+        
+        Output.Value.CommitChanges();
+        
+        return Output.Value;
+    }
+
+    public override bool Validate()
+    {
+        return Radius.Value > 0 && StrokeWidth.Value > 0;
+    }
+}

+ 24 - 4
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ImageLayerNode.cs

@@ -28,10 +28,25 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
 
     public override ChunkyImage OnExecute(KeyFrameTime frame)
     {
-        var imageFrame = frames.FirstOrDefault(x => x.IsInFrame(frame.Frame)); 
-        var result = imageFrame?.Image ?? frames[0].Image;
-        Output.Value = result;
-        return result;
+        var imageFrame = frames.FirstOrDefault(x => x.IsInFrame(frame.Frame));
+        var frameImage = imageFrame?.Image ?? frames[0].Image;
+
+        if (Background.Value != null)
+        {
+            VecI size = GetBiggerSize(frameImage.LatestSize, Background.Value.LatestSize);
+            ChunkyImage combined = new(size);
+            combined.EnqueueDrawChunkyImage(VecI.Zero, Background.Value);
+            combined.EnqueueDrawChunkyImage(VecI.Zero, frameImage);
+            combined.CommitChanges();
+            
+            Output.Value = combined;
+        }
+        else
+        {
+            Output.Value = frameImage;
+        }
+        
+        return Output.Value;
     }
 
     public override void Dispose()
@@ -42,6 +57,11 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
             frame.Image.Dispose();
         }
     }
+    
+    private VecI GetBiggerSize(VecI size1, VecI size2)
+    {
+        return new VecI(Math.Max(size1.X, size2.X), Math.Max(size1.Y, size2.Y));
+    }
 
     IReadOnlyChunkyImage IReadOnlyImageNode.GetLayerImageAtFrame(int frame) => GetLayerImageAtFrame(frame);
 

+ 5 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/MergeNode.cs

@@ -23,6 +23,11 @@ public class MergeNode : Node
 
     public override ChunkyImage? OnExecute(KeyFrameTime frame)
     {
+        if(Top.Value == null && Bottom.Value == null)
+        {
+            return null;
+        }
+        
         VecI size = Top.Value?.CommittedSize ?? Bottom.Value.CommittedSize;
         
         Output.Value = new ChunkyImage(size);

+ 3 - 5
src/PixiEditor.ChangeableDocument/Changes/Structure/CreateStructureMember_Change.cs

@@ -11,15 +11,13 @@ internal class CreateStructureMember_Change : Change
     private Guid newMemberGuid;
 
     private Guid parentFolderGuid;
-    private int parentFolderIndex;
     private StructureMemberType type;
 
     [GenerateMakeChangeAction]
-    public CreateStructureMember_Change(Guid parentFolder, Guid newGuid, int parentFolderIndex,
+    public CreateStructureMember_Change(Guid parentFolder, Guid newGuid,
         StructureMemberType type)
     {
         this.parentFolderGuid = parentFolder;
-        this.parentFolderIndex = parentFolderIndex;
         this.type = type;
         newMemberGuid = newGuid;
     }
@@ -62,9 +60,9 @@ internal class CreateStructureMember_Change : Change
     {
         return type switch
         {
-             StructureMemberType.Layer => CreateLayer_ChangeInfo.FromLayer(parentFolderGuid, parentFolderIndex,
+             StructureMemberType.Layer => CreateLayer_ChangeInfo.FromLayer(parentFolderGuid,
                 (LayerNode)member),
-            StructureMemberType.Folder => CreateFolder_ChangeInfo.FromFolder(parentFolderGuid, parentFolderIndex,
+            StructureMemberType.Folder => CreateFolder_ChangeInfo.FromFolder(parentFolderGuid,
                 (FolderNode)member),
             _ => throw new NotSupportedException(),
         };