flabbet vor 11 Monaten
Ursprung
Commit
544e374e18
22 geänderte Dateien mit 310 neuen und 103 gelöschten Zeilen
  1. 1 0
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/Data/PointsData.cs
  2. 3 3
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/Data/ShapeData.cs
  3. 5 5
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/DistributePointsNode.cs
  4. 3 3
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/EllipseNode.cs
  5. 1 1
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/RasterizeShape.cs
  6. 7 12
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/RemoveClosePointsNode.cs
  7. 7 8
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/ShapeNode.cs
  8. 0 33
      src/PixiEditor.ChangeableDocument/Changeables/Graph/PropertyValidator.cs
  9. 10 0
      src/PixiEditor.ChangeableDocument/Changes/NodeGraph/ConnectProperties_Change.cs
  10. 12 3
      src/PixiEditor.UI.Common/Accents/Base.axaml
  11. 22 0
      src/PixiEditor/Helpers/Converters/SocketColorConverter.cs
  12. 4 0
      src/PixiEditor/Helpers/SerializationUtil.cs
  13. 0 1
      src/PixiEditor/Helpers/ServiceCollectionHelpers.cs
  14. 58 0
      src/PixiEditor/Models/Serialization/Factories/ByteBuilder.cs
  15. 60 0
      src/PixiEditor/Models/Serialization/Factories/ByteExtractor.cs
  16. 47 0
      src/PixiEditor/Models/Serialization/Factories/EllipseSerializationFactory.cs
  17. 42 0
      src/PixiEditor/Models/Serialization/Factories/PointsDataSerializationFactory.cs
  18. 0 28
      src/PixiEditor/Models/Serialization/Factories/ShapeDataSerializationFactory.cs
  19. 4 3
      src/PixiEditor/Styles/Templates/ConnectionView.axaml
  20. 1 1
      src/PixiEditor/Styles/Templates/NodeSocket.axaml
  21. 22 2
      src/PixiEditor/Views/Nodes/NodeGraphView.cs
  22. 1 0
      tests/PixiEditor.Backend.Tests/NodeSystemTests.cs

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/Data/PointsData.cs

@@ -17,6 +17,7 @@ public class PointsData : ShapeData
     {
         using Paint paint = new Paint();
         paint.Color = FillColor;
+        paint.StrokeWidth = StrokeWidth;
         
         drawingSurface.Canvas.DrawPoints(PointMode.Points, Points.Select(p => new Point((int)p.X, (int)p.Y)).ToArray(), paint);
     }

+ 3 - 3
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/Data/ShapeData.cs

@@ -6,9 +6,9 @@ namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes.Data;
 
 public abstract class ShapeData : ICacheable, ICloneable
 {
-    public Color StrokeColor { get; set; }
-    public Color FillColor { get; set; }
-    public int StrokeWidth { get; set; }
+    public Color StrokeColor { get; set; } = Colors.White;
+    public Color FillColor { get; set; } = Colors.White;
+    public int StrokeWidth { get; set; } = 1;
 
     public abstract void Rasterize(DrawingSurface drawingSurface);
     public abstract bool IsValid();

+ 5 - 5
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/DistributePointsNode.cs

@@ -6,7 +6,7 @@ using ShapeData = PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes.D
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes;
 
 [NodeInfo("DistributePoints", "DISTRIBUTE_POINTS", Category = "SHAPE")]
-public class DistributePointsNode : ShapeNode
+public class DistributePointsNode : ShapeNode<PointsData>
 {
     public InputProperty<int> MaxPointCount { get; }
 
@@ -19,12 +19,12 @@ public class DistributePointsNode : ShapeNode
         Seed = CreateInput("Seed", "SEED", 0);
     }
 
-    protected override ShapeData? GetShapeData(RenderingContext context)
+    protected override PointsData? GetShapeData(RenderingContext context)
     {
-        return GetPointsRandomly();
+        return GetPointsRandomly(context.DocumentSize);
     }
 
-    private PointsData GetPointsRandomly()
+    private PointsData GetPointsRandomly(VecI size)
     {
         var seed = Seed.Value;
         var random = new Random(seed);
@@ -33,7 +33,7 @@ public class DistributePointsNode : ShapeNode
         List<VecD> finalPoints = new List<VecD>(pointCount);
         for (int i = 0; i < pointCount; i++)
         {
-            finalPoints.Add(new VecD(random.NextDouble(), random.NextDouble()));
+            finalPoints.Add(new VecD(random.NextDouble() * size.X, random.NextDouble() * size.Y));
         }
         
         var shapeData = new PointsData(finalPoints);

+ 3 - 3
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/EllipseNode.cs

@@ -7,7 +7,7 @@ using ShapeData = PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes.D
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes;
 
 [NodeInfo("Ellipse", "ELLIPSE_NODE", Category = "SHAPE")]
-public class EllipseNode : ShapeNode
+public class EllipseNode : ShapeNode<EllipseData>
 {
     public InputProperty<VecD> Position { get; }
     public InputProperty<VecD> Radius { get; }
@@ -19,13 +19,13 @@ public class EllipseNode : ShapeNode
     {
         Position = CreateInput<VecD>("Position", "POSITION", VecI.Zero);
         Radius = CreateInput<VecD>("Radius", "RADIUS", new VecD(32, 32)).WithRules(
-            v => v.Min(VecI.One));
+            v => v.Min(new VecD(1)));
         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);
     }
 
-    protected override ShapeData? GetShapeData(RenderingContext context)
+    protected override EllipseData? GetShapeData(RenderingContext context)
     {
         return new EllipseData(Position.Value, Radius.Value)
             { StrokeColor = StrokeColor.Value, FillColor = FillColor.Value, StrokeWidth = StrokeWidth.Value };

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/RasterizeShape.cs

@@ -19,7 +19,7 @@ public class RasterizeShape : Node
     public RasterizeShape()
     {
         Image = CreateOutput<Texture>("Image", "IMAGE", null);
-        Data = CreateInput<ShapeData>("Points", "POINTS", null);
+        Data = CreateInput<ShapeData>("Points", "SHAPE", null);
     }
 
     protected override Texture? OnExecute(RenderingContext context)

+ 7 - 12
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/RemoveClosePointsNode.cs

@@ -7,9 +7,9 @@ using ShapeData = PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes.D
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes;
 
 [NodeInfo("RemoveClosePoints", "REMOVE_CLOSE_POINTS", Category = "SHAPE")]
-public class RemoveClosePointsNode : ShapeNode
+public class RemoveClosePointsNode : ShapeNode<PointsData>
 {
-    public InputProperty<ShapeData> Input { get; }
+    public InputProperty<PointsData> Input { get; }
 
     public InputProperty<double> MinDistance { get; }
 
@@ -17,28 +17,23 @@ public class RemoveClosePointsNode : ShapeNode
 
     public RemoveClosePointsNode()
     {
-        Input = CreateInput<ShapeData>("Input", "POINTS", null);
+        Input = CreateInput<PointsData>("Input", "POINTS", null);
         MinDistance = CreateInput("MinDistance", "MIN_DISTANCE", 0d);
         Seed = CreateInput("Seed", "SEED", 0);
     }
 
-    protected override ShapeData? GetShapeData(RenderingContext context)
+    protected override PointsData? GetShapeData(RenderingContext context)
     {
         var data = Input.Value;
 
-        if (data is not PointsData pointsData)
-        {
-            return data;
-        }
-
         var distance = MinDistance.Value;
 
-        if (distance == 0)
+        if (distance == 0 || data == null || data.Points == null)
         {
             return null;
         }
 
-        var availablePoints = pointsData.Points.Distinct().ToList();
+        var availablePoints = data.Points.Distinct().ToList();
         List<VecD> newPoints = new List<VecD>();
         
         var minDistance = MinDistance.Value;
@@ -61,7 +56,7 @@ public class RemoveClosePointsNode : ShapeNode
             continue;
 
             bool InRange(VecD other) =>
-                (other.Multiply(documentSize) - point.Multiply(documentSize)).Length <= minDistance;
+                (other - point).Length <= minDistance;
         }
 
         if (availablePoints.Count == 1)

+ 7 - 8
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/ShapeNode.cs

@@ -5,14 +5,13 @@ using ShapeData = PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes.D
 
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes;
 
-public abstract class ShapeNode : Node
+public abstract class ShapeNode<T> : Node where T : ShapeData
 {
-    public OutputProperty<ShapeData> Output { get; }
-    private const int PreviewSize = 150;
+    public OutputProperty<T> Output { get; }
     
     public ShapeNode()
     {
-        Output = CreateOutput<ShapeData>("Output", "OUTPUT", null);
+        Output = CreateOutput<T>("Output", "OUTPUT", null);
     }
 
     protected override Texture? OnExecute(RenderingContext context)
@@ -24,14 +23,14 @@ public abstract class ShapeNode : Node
         if (data == null || !data.IsValid())
             return null;
 
-        return RasterizePreview(data);
+        return RasterizePreview(data, context.DocumentSize);
     }
     
-    protected abstract ShapeData? GetShapeData(RenderingContext context);
+    protected abstract T? GetShapeData(RenderingContext context);
 
-    public Texture RasterizePreview(ShapeData data)
+    public Texture RasterizePreview(ShapeData data, VecI size)
     {
-        Texture texture = RequestTexture(0, new VecI(PreviewSize, PreviewSize));
+        Texture texture = RequestTexture(0, size);
         
         data.Rasterize(texture.DrawingSurface);
         

+ 0 - 33
src/PixiEditor.ChangeableDocument/Changeables/Graph/PropertyValidator.cs

@@ -44,39 +44,6 @@ public class PropertyValidator
         return min;
     }
 
-    /*public PropertyValidator Select<T>(Func<T, object> selector)
-    {
-        PropertyValidator newValidator = new();
-
-        newValidator.Rules.Add(v =>
-        {
-            if (v is T val)
-            {
-                return (true, selector(val));
-            }
-
-            return (false, v);
-        });
-
-        return newValidator;
-    }
-
-    public void All(params PropertyValidator[] validators)
-    {
-        Rules.Add(v =>
-        {
-            foreach (var validator in validators)
-            {
-                if (!validator.Validate(v))
-                {
-                    return (false, validator.GetClosestValidValue(v));
-                }
-            }
-
-            return (true, v);
-        });
-    }*/
-
     public bool Validate(object? value)
     {
         object lastValue = value;

+ 10 - 0
src/PixiEditor.ChangeableDocument/Changes/NodeGraph/ConnectProperties_Change.cs

@@ -138,6 +138,16 @@ internal class ConnectProperties_Change : Change
                 return ConversionTable.TryConvert(result, output.ValueType, out _);
             }
 
+            if (outputValue == null)
+            {
+                return true;
+            }
+            
+            if (outputValue.GetType().IsAssignableTo(input.ValueType))
+            {
+                return true;
+            }
+
             if (ConversionTable.TryConvert(outputValue, input.ValueType, out _))
             {
                 return true;

+ 12 - 3
src/PixiEditor.UI.Common/Accents/Base.axaml

@@ -43,7 +43,7 @@
             <!--                          -->
             
             <!-- Sockets -->
-            <Color x:Key="DefaultSocketColor">#c0334e</Color>
+            <Color x:Key="DefaultSocketColor">#FF00FF</Color>
             <Color x:Key="ImageSocketColor">#99c47a</Color>
             <Color x:Key="FilterSocketColor">#CC5C5C</Color>
             <Color x:Key="BoolSocketColor">#68abdf</Color>
@@ -53,7 +53,14 @@
             <Color x:Key="VecDSocketColor">#c984ca</Color>
             <Color x:Key="VecISocketColor">#c9b4ca</Color>
             <Color x:Key="IntSocketColor">#4C64B1</Color>
-            <Color x:Key="PointListSocketColor">#7f5280</Color>
+            <Color x:Key="EllipseDataSocketColor">#a473a5</Color>
+            <Color x:Key="PointsDataSocketColor">#e1d0e1</Color>
+            <GradientStops x:Key="ShapeDataSocketGradient">
+                <GradientStop Offset="0" Color="{StaticResource EllipseDataSocketColor}"/>
+                <GradientStop Offset="0.5" Color="{StaticResource EllipseDataSocketColor}"/>
+                <GradientStop Offset="0.5" Color="{StaticResource PointsDataSocketColor}"/>
+                <GradientStop Offset="1" Color="{StaticResource PointsDataSocketColor}"/>
+            </GradientStops>
             
             <!-- Zones & Frames -->
             <Color x:Key="PixiEditorModifyImageBorderColor">#68abdf</Color>
@@ -129,7 +136,9 @@
             <SolidColorBrush x:Key="Int2SocketBrush" Color="{StaticResource VecISocketColor}"/>
             <SolidColorBrush x:Key="Int32SocketBrush" Color="{StaticResource IntSocketColor}"/>
             <SolidColorBrush x:Key="Int1SocketBrush" Color="{StaticResource IntSocketColor}"/>
-            <SolidColorBrush x:Key="PointListSocketBrush" Color="{StaticResource PointListSocketColor}"/>
+            <ConicGradientBrush x:Key="ShapeDataSocketBrush" GradientStops="{StaticResource ShapeDataSocketGradient}"/>
+            <SolidColorBrush x:Key="EllipseDataSocketBrush" Color="{StaticResource EllipseDataSocketColor}"/>
+            <SolidColorBrush x:Key="PointsDataSocketBrush" Color="{StaticResource PointsDataSocketColor}"/>
             
             <!-- Zones & Frames -->
             <SolidColorBrush x:Key="PixiEditorModifyImageLeftBorderBrush" Color="{StaticResource PixiEditorModifyImageBorderColor}"/>

+ 22 - 0
src/PixiEditor/Helpers/Converters/SocketColorConverter.cs

@@ -0,0 +1,22 @@
+using System.Globalization;
+using Avalonia.Media;
+using Colors = PixiEditor.DrawingApi.Core.ColorsImpl.Colors;
+
+namespace PixiEditor.Helpers.Converters;
+
+internal class SocketColorConverter : SingleInstanceConverter<SocketColorConverter>
+{
+    Color unknownColor = Color.FromRgb(255, 0, 255);
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        if (value is IBrush brush)
+        {
+            if(brush is SolidColorBrush solidColorBrush)
+                return solidColorBrush.Color;
+            if (brush is GradientBrush linearGradientBrush)
+                return linearGradientBrush.GradientStops.FirstOrDefault()?.Color ?? unknownColor;
+        }
+        
+        return unknownColor;
+    }
+}

+ 4 - 0
src/PixiEditor/Helpers/SerializationUtil.cs

@@ -26,6 +26,10 @@ public static class SerializationUtil
         }
 
         var factory = allFactories.FirstOrDefault(x => x.OriginalType == value.GetType());
+        if (factory == null)
+        {
+            factory = allFactories.FirstOrDefault(x => value.GetType().IsAssignableTo(x.OriginalType));
+        }
 
         if (factory != null)
         {

+ 0 - 1
src/PixiEditor/Helpers/ServiceCollectionHelpers.cs

@@ -123,7 +123,6 @@ internal static class ServiceCollectionHelpers
             .AddSingleton<SerializationFactory, VecISerializationFactory>()
             .AddSingleton<SerializationFactory, ColorSerializationFactory>()
             .AddSingleton<SerializationFactory, ColorMatrixSerializationFactory>()
-            .AddSingleton<SerializationFactory, ShapeDataSerializationFactory>()
             .AddSingleton<SerializationFactory, VecD3SerializationFactory>()
             .AddSingleton<SerializationFactory, TextureSerializationFactory>()
             // Palette Parsers

+ 58 - 0
src/PixiEditor/Models/Serialization/Factories/ByteBuilder.cs

@@ -0,0 +1,58 @@
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.Numerics;
+
+namespace PixiEditor.Models.Serialization.Factories;
+
+public class ByteBuilder
+{
+    public byte[] Data { get; private set; }
+    
+    private List<byte> _data = new List<byte>();
+    
+    public ByteBuilder AddVecD(VecD vec)
+    {
+        _data.AddRange(BitConverter.GetBytes(vec.X));
+        _data.AddRange(BitConverter.GetBytes(vec.Y));
+        
+        return this;
+    }
+    
+    public ByteBuilder AddColor(Color color)
+    {
+        _data.Add(color.R);
+        _data.Add(color.G);
+        _data.Add(color.B);
+        _data.Add(color.A);
+        
+        return this;
+    }
+    
+    public ByteBuilder AddInt(int value)
+    {
+        _data.AddRange(BitConverter.GetBytes(value));
+        
+        return this;
+    }
+    
+    public ByteBuilder AddDouble(double value)
+    {
+        _data.AddRange(BitConverter.GetBytes(value));
+        
+        return this;
+    }
+    
+    public byte[] Build()
+    {
+        Data = _data.ToArray();
+        return Data;
+    }
+
+    public void AddVecDList(List<VecD> originalPoints)
+    {
+        AddInt(originalPoints.Count);
+        foreach (var point in originalPoints)
+        {
+            AddVecD(point);
+        }
+    }
+}

+ 60 - 0
src/PixiEditor/Models/Serialization/Factories/ByteExtractor.cs

@@ -0,0 +1,60 @@
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.Numerics;
+
+namespace PixiEditor.Models.Serialization.Factories;
+
+public class ByteExtractor
+{
+    public int Position { get; private set; }
+    
+    private byte[] _data;
+    
+    public ByteExtractor(byte[] data)
+    {
+        _data = data;
+    }
+    
+    public VecD GetVecD()
+    {
+        double x = BitConverter.ToDouble(_data, Position);
+        double y = BitConverter.ToDouble(_data, Position + sizeof(double));
+        
+        Position += sizeof(double) * 2;
+        
+        return new VecD(x, y);
+    }
+    
+    public Color GetColor()
+    {
+        byte r = _data[Position];
+        byte g = _data[Position + 1];
+        byte b = _data[Position + 2];
+        byte a = _data[Position + 3];
+        
+        Position += 4;
+        
+        return new Color(r, g, b, a);
+    }
+    
+    public int GetInt()
+    {
+        int value = BitConverter.ToInt32(_data, Position);
+        
+        Position += sizeof(int);
+        
+        return value;
+    }
+
+    public List<VecD> GetVecDList()
+    {
+        int count = GetInt();
+        List<VecD> points = new List<VecD>();
+        
+        for (int i = 0; i < count; i++)
+        {
+            points.Add(GetVecD());
+        }
+        
+        return points;
+    }
+}

+ 47 - 0
src/PixiEditor/Models/Serialization/Factories/EllipseSerializationFactory.cs

@@ -0,0 +1,47 @@
+using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes.Data;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.Numerics;
+
+namespace PixiEditor.Models.Serialization.Factories;
+
+public class EllipseSerializationFactory : SerializationFactory<byte[], EllipseData>
+{
+    public override string DeserializationId { get; } = "PixiEditor.EllipseData";
+    public override byte[] Serialize(EllipseData original)
+    {
+        ByteBuilder builder = new ByteBuilder();
+        builder.AddVecD(original.Center);
+        builder.AddVecD(original.Radius);
+        builder.AddColor(original.StrokeColor);
+        builder.AddColor(original.FillColor);
+        builder.AddInt(original.StrokeWidth);
+        
+        return builder.Build();
+    }
+
+    public override bool TryDeserialize(object serialized, out EllipseData original)
+    {
+        if (serialized is not byte[] data)
+        {
+            original = null;
+            return false;
+        }
+        
+        ByteExtractor extractor = new ByteExtractor(data);
+        
+        VecD center = extractor.GetVecD();
+        VecD radius = extractor.GetVecD();
+        Color strokeColor = extractor.GetColor();
+        Color fillColor = extractor.GetColor();
+        int strokeWidth = extractor.GetInt();
+        
+        original = new EllipseData(center, radius)
+        {
+            StrokeColor = strokeColor,
+            FillColor = fillColor,
+            StrokeWidth = strokeWidth
+        };
+        
+        return true;
+    }
+}

+ 42 - 0
src/PixiEditor/Models/Serialization/Factories/PointsDataSerializationFactory.cs

@@ -0,0 +1,42 @@
+using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes.Data;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.Numerics;
+
+namespace PixiEditor.Models.Serialization.Factories;
+
+public class PointsDataSerializationFactory : SerializationFactory<byte[], PointsData>
+{
+    public override string DeserializationId { get; } = "PixiEditor.PointsData";
+    public override byte[] Serialize(PointsData original)
+    {
+        ByteBuilder builder = new ByteBuilder();
+        builder.AddVecDList(original.Points);
+        builder.AddColor(original.FillColor);
+        builder.AddInt(original.StrokeWidth);
+        
+        return builder.Build();
+    }
+
+    public override bool TryDeserialize(object serialized, out PointsData original)
+    {
+        if (serialized is not byte[] data)
+        {
+            original = null;
+            return false;
+        }
+        
+        ByteExtractor extractor = new ByteExtractor(data);
+        
+        List<VecD> points = extractor.GetVecDList();
+        Color fillColor = extractor.GetColor();
+        int strokeWidth = extractor.GetInt();
+        
+        original = new PointsData(points)
+        {
+            FillColor = fillColor,
+            StrokeWidth = strokeWidth
+        };
+        
+        return true;
+    }
+}

+ 0 - 28
src/PixiEditor/Models/Serialization/Factories/ShapeDataSerializationFactory.cs

@@ -1,28 +0,0 @@
-using MessagePack;
-using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes;
-using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes.Data;
-
-namespace PixiEditor.Models.Serialization.Factories;
-
-public class ShapeDataSerializationFactory : SerializationFactory<byte[], ShapeData>
-{
-    public override string DeserializationId { get; } = "PixiEditor.PointList";
-
-    public override byte[] Serialize(ShapeData original)
-    {
-        return MessagePackSerializer.Serialize(original);
-    }
-
-    public override bool TryDeserialize(object serialized, out ShapeData? original)
-    {
-        if (serialized is not byte[] buffer)
-        {
-            original = null;
-            return false;
-        }
-        
-        original = MessagePackSerializer.Deserialize<ShapeData>(buffer);
-
-        return true;
-    }
-}

+ 4 - 3
src/PixiEditor/Styles/Templates/ConnectionView.axaml

@@ -1,6 +1,7 @@
 <ResourceDictionary xmlns="https://github.com/avaloniaui"
                     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-                    xmlns:nodes="clr-namespace:PixiEditor.Views.Nodes">
+                    xmlns:nodes="clr-namespace:PixiEditor.Views.Nodes"
+                    xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters">
 
     <ControlTheme TargetType="nodes:ConnectionView" x:Key="{x:Type nodes:ConnectionView}">
         <Setter Property="ClipToBounds" Value="False"/>
@@ -14,8 +15,8 @@
                             <LinearGradientBrush>
                                 <LinearGradientBrush.GradientStops>
                                     <GradientStop Offset="0" Color="#555" />
-                                    <GradientStop Offset=".05" Color="{Binding InputProperty.SocketBrush.Color, RelativeSource={RelativeSource TemplatedParent}}" />
-                                    <GradientStop Offset="0.95" Color="{Binding OutputProperty.SocketBrush.Color, RelativeSource={RelativeSource TemplatedParent}}" />
+                                    <GradientStop Offset=".05" Color="{Binding InputProperty.SocketBrush, RelativeSource={RelativeSource TemplatedParent}, Converter={converters:SocketColorConverter}}" />
+                                    <GradientStop Offset="0.95" Color="{Binding OutputProperty.SocketBrush, RelativeSource={RelativeSource TemplatedParent}, Converter={converters:SocketColorConverter}}" />
                                     <GradientStop Offset="1" Color="#555" />
                                 </LinearGradientBrush.GradientStops>
                             </LinearGradientBrush>

+ 1 - 1
src/PixiEditor/Styles/Templates/NodeSocket.axaml

@@ -8,7 +8,7 @@
                     <Grid Name="PART_ConnectPort">
                         <Panel Width="20" Height="20" Margin="-5, 0" Background="Transparent"
                                IsVisible="{Binding !IsFunc, RelativeSource={RelativeSource TemplatedParent}}">
-                            <Ellipse Width="10" Height="10"
+                            <Ellipse Width="10" Height="10" RenderTransform="rotate(90deg)"
                                      Fill="{TemplateBinding SocketBrush}" />
                         </Panel>
                         <Panel Margin="-5, 0" Width="20" Height="20" Background="Transparent"

+ 22 - 2
src/PixiEditor/Views/Nodes/NodeGraphView.cs

@@ -250,7 +250,7 @@ internal class NodeGraphView : Zoombox.Zoombox
 
             Color gradientStopFirstColor = _startingPropColor;
             Color gradientStopSecondColor =
-                ((SolidColorBrush)nodeSocket?.SocketBrush)?.Color ?? gradientStopFirstColor;
+                GetSocketColor(nodeSocket) ?? gradientStopFirstColor;
 
             if (endPoint.X > startDragConnectionPoint.X)
             {
@@ -276,6 +276,26 @@ internal class NodeGraphView : Zoombox.Zoombox
         }
     }
 
+    private static Color? GetSocketColor(NodeSocket? nodeSocket)
+    {
+        if (nodeSocket == null)
+        {
+            return null;
+        }
+
+        if (nodeSocket.SocketBrush is SolidColorBrush solidColor)
+        {
+            return solidColor.Color;
+        }
+
+        if (nodeSocket.SocketBrush is GradientBrush gradientBrush)
+        {
+            return gradientBrush.GradientStops.FirstOrDefault()?.Color;
+        }
+        
+        return null; 
+    }
+
     protected override void OnPointerReleased(PointerReleasedEventArgs e)
     {
         base.OnPointerReleased(e);
@@ -353,7 +373,7 @@ internal class NodeGraphView : Zoombox.Zoombox
         }
 
         _previewConnectionLine.IsVisible = true;
-        _startingPropColor = ((SolidColorBrush)nodeSocket.SocketBrush).Color;
+        _startingPropColor = GetSocketColor(nodeSocket) ?? Colors.White; 
         _previewConnectionLine.LineBrush = new LinearGradientBrush()
         {
             GradientStops = new GradientStops()

+ 1 - 0
tests/PixiEditor.Backend.Tests/NodeSystemTests.cs

@@ -144,6 +144,7 @@ public class NodeSystemTests
             foreach (var input in node.InputProperties)
             {
                 if (knownNonSerializableTypes.Contains(input.ValueType)) continue;
+                if(input.ValueType.IsAbstract) continue;
                 if (input.ValueType.IsAssignableTo(typeof(Delegate))) continue;
                 bool hasFactory = factories.Any(x => x.OriginalType == input.ValueType);
                 Assert.True(