Browse Source

Merge pull request #735 from PixiEditor/fixes/22.01.2025

Fixes/22.01.2025
Krzysztof Krysiński 6 months ago
parent
commit
19896b45ef

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Context/FuncContext.cs

@@ -129,7 +129,7 @@ public class FuncContext
             return constantHalf4;
             return constantHalf4;
         }
         }
 
 
-        return Builder.AssignNewHalf4(Builder.Functions.GetHslToRgb(h, s, v, a));
+        return Builder.AssignNewHalf4(Builder.Functions.GetHsvToRgb(h, s, v, a));
     }
     }
 
 
     public Half4 HslaToRgba(Expression h, Expression s, Expression l, Expression a)
     public Half4 HslaToRgba(Expression h, Expression s, Expression l, Expression a)

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

@@ -47,7 +47,7 @@ public class PointsVectorData : ShapeVectorData
             canvas.SetMatrix(final);
             canvas.SetMatrix(final);
         }
         }
 
 
-        canvas.DrawPoints(PointMode.Points, Points.Select(p => new VecF((int)p.X, (int)p.Y)).ToArray(),
+        canvas.DrawPoints(PointMode.Points, Points.Select(p => new VecF((float)p.X, (float)p.Y)).ToArray(),
             paint);
             paint);
 
 
         if (applyTransform)
         if (applyTransform)

+ 114 - 47
src/PixiEditor.ChangeableDocument/Changes/NodeGraph/ConnectProperties_Change.cs

@@ -14,7 +14,8 @@ internal class ConnectProperties_Change : Change
     public string InputProperty { get; }
     public string InputProperty { get; }
     public string OutputProperty { get; }
     public string OutputProperty { get; }
 
 
-    private IOutputProperty? originalConnection;
+    private PropertyConnection originalConnection;
+    private List<PropertyConnection> originalConnectionsAtOutput;
 
 
     [GenerateMakeChangeAction]
     [GenerateMakeChangeAction]
     public ConnectProperties_Change(Guid inputNodeId, Guid outputNodeId, string inputProperty, string outputProperty)
     public ConnectProperties_Change(Guid inputNodeId, Guid outputNodeId, string inputProperty, string outputProperty)
@@ -38,12 +39,21 @@ internal class ConnectProperties_Change : Change
         InputProperty? inputProp = inputNode.GetInputProperty(InputProperty);
         InputProperty? inputProp = inputNode.GetInputProperty(InputProperty);
         OutputProperty? outputProp = outputNode.GetOutputProperty(OutputProperty);
         OutputProperty? outputProp = outputNode.GetOutputProperty(OutputProperty);
 
 
+        if (inputNode == outputNode && outputProp == null)
+        {
+            var input = inputNode.GetInputProperty(OutputProperty);
+            if (input is { Connection: not null })
+            {
+                outputProp = input.Connection as OutputProperty;
+            }
+        }
+
         if (inputProp == null || outputProp == null)
         if (inputProp == null || outputProp == null)
         {
         {
             return false;
             return false;
         }
         }
-        
-        if(IsLoop(inputProp, outputProp))
+
+        if (IsLoop(inputProp, outputProp))
         {
         {
             return false;
             return false;
         }
         }
@@ -55,35 +65,17 @@ internal class ConnectProperties_Change : Change
             return false;
             return false;
         }
         }
 
 
-        originalConnection = inputProp.Connection;
+        originalConnection =
+            new PropertyConnection(inputProp.Connection?.Node.Id, inputProp.Connection?.InternalPropertyName);
+        originalConnectionsAtOutput = new List<PropertyConnection>();
 
 
-        return true;
-    }
-    
-    private bool IsLoop(InputProperty input, OutputProperty output)
-    {
-        if (input.Node == output.Node)
+        foreach (var connection in outputProp.Connections)
         {
         {
-            return true;
-        }
-        if(input.Node.OutputProperties.Any(x => x.Connections.Any(y => y.Node == output.Node)))
-        {
-            return true;
+            originalConnectionsAtOutput.Add(new PropertyConnection(connection.Node.Id,
+                connection.InternalPropertyName));
         }
         }
-        
-        bool isLoop = false;
-        input.Node.TraverseForwards(x =>
-        {
-            if (x == output.Node)
-            {
-                isLoop = true;
-                return false;
-            }
-
-            return true;
-        });
 
 
-        return isLoop;
+        return true;
     }
     }
 
 
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, bool firstApply,
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, bool firstApply,
@@ -95,11 +87,32 @@ internal class ConnectProperties_Change : Change
         InputProperty inputProp = inputNode.GetInputProperty(InputProperty);
         InputProperty inputProp = inputNode.GetInputProperty(InputProperty);
         OutputProperty outputProp = outputNode.GetOutputProperty(OutputProperty);
         OutputProperty outputProp = outputNode.GetOutputProperty(OutputProperty);
 
 
+        List<IChangeInfo> changes = new();
+
+        if (inputNode == outputNode && outputProp == null)
+        {
+            var input = inputNode.GetInputProperty(OutputProperty);
+            if (input is { Connection: not null })
+            {
+                outputProp = input.Connection as OutputProperty;
+
+                if (outputProp != null)
+                {
+                    changes.Add(new ConnectProperty_ChangeInfo(null, inputNode.Id, null, OutputProperty));
+                }
+
+                outputProp.DisconnectFrom(input);
+            }
+        }
+
         outputProp.ConnectTo(inputProp);
         outputProp.ConnectTo(inputProp);
 
 
         ignoreInUndo = false;
         ignoreInUndo = false;
 
 
-        return new ConnectProperty_ChangeInfo(outputNode.Id, inputNode.Id, OutputProperty, InputProperty);
+        changes.Add(new ConnectProperty_ChangeInfo(outputProp.Node.Id, InputNodeId, outputProp.InternalPropertyName,
+            InputProperty));
+        
+        return changes;
     }
     }
 
 
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
@@ -110,25 +123,79 @@ internal class ConnectProperties_Change : Change
         InputProperty inputProp = inputNode.GetInputProperty(InputProperty);
         InputProperty inputProp = inputNode.GetInputProperty(InputProperty);
         OutputProperty outputProp = outputNode.GetOutputProperty(OutputProperty);
         OutputProperty outputProp = outputNode.GetOutputProperty(OutputProperty);
 
 
-        outputProp.DisconnectFrom(inputProp);
+        List<IChangeInfo> changes = new();
+
+        if (inputNode == outputNode && outputProp == null)
+        {
+            var input = inputNode.GetInputProperty(OutputProperty);
 
 
-        ConnectProperty_ChangeInfo change = new(null, InputNodeId, null, InputProperty);
+            if (inputProp.Connection != null)
+            {
+                inputProp.Connection.ConnectTo(input);
+                changes.Add(new ConnectProperty_ChangeInfo(inputProp.Connection.Node.Id, input.Node.Id,
+                    inputProp.Connection.InternalPropertyName, input.InternalPropertyName));
+                
+                outputProp = input.Connection as OutputProperty;
+            }
+        }
 
 
-        inputProp.Connection = originalConnection;
+        outputProp.DisconnectFrom(inputProp);
 
 
-        List<IChangeInfo> changes = new() { change, };
+        changes.Add(new ConnectProperty_ChangeInfo(null, InputNodeId, null, InputProperty));
 
 
-        if (originalConnection != null)
+        if (originalConnection.NodeId != null)
         {
         {
-            ConnectProperty_ChangeInfo oldConnection = new(originalConnection.Node.Id, InputNodeId,
-                originalConnection.InternalPropertyName, InputProperty);
-            changes.Add(oldConnection);
+            Node originalNode = target.FindNode(originalConnection.NodeId.Value);
+            IOutputProperty? originalOutput = originalNode.GetOutputProperty(originalConnection.PropertyName);
+            originalOutput.ConnectTo(inputProp);
+
+            changes.Add(new ConnectProperty_ChangeInfo(originalOutput.Node.Id, inputProp.Node.Id,
+                originalOutput.InternalPropertyName, InputProperty));
         }
         }
 
 
+        foreach (var connection in originalConnectionsAtOutput)
+        {
+            if (connection.NodeId.HasValue)
+            {
+                Node originalNode = target.FindNode(connection.NodeId.Value);
+                IInputProperty? originalInput = originalNode.GetInputProperty(connection.PropertyName);
+                outputProp.ConnectTo(originalInput);
+
+                changes.Add(new ConnectProperty_ChangeInfo(outputProp.Node.Id, originalInput.Node.Id,
+                    outputProp.InternalPropertyName, originalInput.InternalPropertyName));
+            }
+        }
 
 
         return changes;
         return changes;
     }
     }
 
 
+    private bool IsLoop(InputProperty input, OutputProperty output)
+    {
+        if (input.Node == output.Node)
+        {
+            return true;
+        }
+
+        if (input.Node.OutputProperties.Any(x => x.Connections.Any(y => y.Node == output.Node)))
+        {
+            return true;
+        }
+
+        bool isLoop = false;
+        input.Node.TraverseForwards(x =>
+        {
+            if (x == output.Node)
+            {
+                isLoop = true;
+                return false;
+            }
+
+            return true;
+        });
+
+        return isLoop;
+    }
+
     private static bool CheckTypeCompatibility(InputProperty input, OutputProperty output)
     private static bool CheckTypeCompatibility(InputProperty input, OutputProperty output)
     {
     {
         if (input.ValueType != output.ValueType)
         if (input.ValueType != output.ValueType)
@@ -139,17 +206,17 @@ internal class ConnectProperties_Change : Change
             }
             }
 
 
             object? outputValue = output.Value;
             object? outputValue = output.Value;
-            
-            if(IsExpressionToConstant(output, input, out var result))
+
+            if (IsExpressionToConstant(output, input, out var result))
             {
             {
                 outputValue = result;
                 outputValue = result;
             }
             }
-            
-            if(IsConstantToExpression(input, outputValue, out result))
+
+            if (IsConstantToExpression(input, outputValue, out result))
             {
             {
                 return ConversionTable.TryConvert(result, output.ValueType, out _);
                 return ConversionTable.TryConvert(result, output.ValueType, out _);
             }
             }
-            
+
             if (output.ValueType.IsAssignableTo(input.ValueType))
             if (output.ValueType.IsAssignableTo(input.ValueType))
             {
             {
                 return true;
                 return true;
@@ -165,7 +232,7 @@ internal class ConnectProperties_Change : Change
 
 
         return true;
         return true;
     }
     }
-    
+
     private static bool IsConstantToExpression(InputProperty input, object objValue, out object result)
     private static bool IsConstantToExpression(InputProperty input, object objValue, out object result)
     {
     {
         if (input.Value is Delegate func && func.Method.ReturnType.IsAssignableTo(typeof(ShaderExpressionVariable)))
         if (input.Value is Delegate func && func.Method.ReturnType.IsAssignableTo(typeof(ShaderExpressionVariable)))
@@ -173,7 +240,7 @@ internal class ConnectProperties_Change : Change
             try
             try
             {
             {
                 var actualArg = func.DynamicInvoke(FuncContext.NoContext);
                 var actualArg = func.DynamicInvoke(FuncContext.NoContext);
-                if(actualArg is ShaderExpressionVariable variable)
+                if (actualArg is ShaderExpressionVariable variable)
                 {
                 {
                     result = variable.GetConstant();
                     result = variable.GetConstant();
                     return true;
                     return true;
@@ -197,11 +264,11 @@ internal class ConnectProperties_Change : Change
             try
             try
             {
             {
                 o = func.DynamicInvoke(FuncContext.NoContext);
                 o = func.DynamicInvoke(FuncContext.NoContext);
-                if(o is ShaderExpressionVariable variable)
+                if (o is ShaderExpressionVariable variable)
                 {
                 {
                     o = variable.GetConstant();
                     o = variable.GetConstant();
                 }
                 }
-                
+
                 return true;
                 return true;
             }
             }
             catch
             catch
@@ -221,7 +288,7 @@ internal class ConnectProperties_Change : Change
         {
         {
             return secondType.IsAssignableTo(typeof(Delegate));
             return secondType.IsAssignableTo(typeof(Delegate));
         }
         }
-        
+
         return false;
         return false;
     }
     }
 }
 }

+ 0 - 1
src/PixiEditor/Data/Localization/Languages/en.json

@@ -493,7 +493,6 @@
   "RESET_VIEWPORT": "Reset viewport",
   "RESET_VIEWPORT": "Reset viewport",
   "VIEWPORT_SETTINGS": "Viewport settings",
   "VIEWPORT_SETTINGS": "Viewport settings",
   "MOVE_TOOL_ACTION_DISPLAY_TRANSFORMING": "Click and hold mouse to move pixels in selected layers.",
   "MOVE_TOOL_ACTION_DISPLAY_TRANSFORMING": "Click and hold mouse to move pixels in selected layers.",
-  "MOVE_TOOL_ACTION_DISPLAY_CTRL": "Hold mouse to move all layers.",
   "CTRL_KEY": "Ctrl",
   "CTRL_KEY": "Ctrl",
   "SHIFT_KEY": "Shift",
   "SHIFT_KEY": "Shift",
   "ALT_KEY": "Alt",
   "ALT_KEY": "Alt",

+ 10 - 14
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/ShiftLayerExecutor.cs

@@ -20,27 +20,22 @@ internal class ShiftLayerExecutor : UpdateableChangeExecutor
     public override ExecutionState Start()
     public override ExecutionState Start()
     {
     {
         IStructureMemberHandler? member = document!.SelectedStructureMember;
         IStructureMemberHandler? member = document!.SelectedStructureMember;
-        
+
         tool = GetHandler<IMoveToolHandler>();
         tool = GetHandler<IMoveToolHandler>();
         if (tool is null)
         if (tool is null)
             return ExecutionState.Error;
             return ExecutionState.Error;
 
 
-        if (tool.MoveAllLayers)
-        {
-            _affectedMemberGuids.AddRange(document.StructureHelper.GetAllLayers().Select(x => x.Id));
-        }
-        else
-        {
-            if (member != null)
-                _affectedMemberGuids.Add(member.Id);
-            _affectedMemberGuids.AddRange(document!.SoftSelectedStructureMembers.Select(x => x.Id));
-        }
+
+        if (member != null)
+            _affectedMemberGuids.Add(member.Id);
+        _affectedMemberGuids.AddRange(document!.SoftSelectedStructureMembers.Select(x => x.Id));
 
 
         RemoveDrawOnMaskLayers(_affectedMemberGuids);
         RemoveDrawOnMaskLayers(_affectedMemberGuids);
-        
+
         startPos = controller!.LastPixelPosition;
         startPos = controller!.LastPixelPosition;
 
 
-        ShiftLayer_Action action = new(_affectedMemberGuids, VecI.Zero, tool.KeepOriginalImage, document!.AnimationHandler.ActiveFrameBindable);
+        ShiftLayer_Action action = new(_affectedMemberGuids, VecI.Zero, tool.KeepOriginalImage,
+            document!.AnimationHandler.ActiveFrameBindable);
         internals!.ActionAccumulator.AddActions(action);
         internals!.ActionAccumulator.AddActions(action);
 
 
         return ExecutionState.Success;
         return ExecutionState.Success;
@@ -61,7 +56,8 @@ internal class ShiftLayerExecutor : UpdateableChangeExecutor
 
 
     public override void OnPixelPositionChange(VecI pos)
     public override void OnPixelPositionChange(VecI pos)
     {
     {
-        ShiftLayer_Action action = new(_affectedMemberGuids, pos - startPos, tool!.KeepOriginalImage, document!.AnimationHandler.ActiveFrameBindable);
+        ShiftLayer_Action action = new(_affectedMemberGuids, pos - startPos, tool!.KeepOriginalImage,
+            document!.AnimationHandler.ActiveFrameBindable);
         internals!.ActionAccumulator.AddActions(action);
         internals!.ActionAccumulator.AddActions(action);
     }
     }
 
 

+ 2 - 11
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/TransformSelectedExecutor.cs

@@ -43,10 +43,8 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
         tool.TransformingSelectedArea = true;
         tool.TransformingSelectedArea = true;
         List<IStructureMemberHandler> members = new();
         List<IStructureMemberHandler> members = new();
 
 
-        members = document.SoftSelectedStructureMembers
-            .Append(document.SelectedStructureMember)
-            .Where(static m => m is ILayerHandler)
-            .Distinct().ToList();
+        var guids = document.ExtractSelectedLayers(false);
+        members = guids.Select(g => document.StructureHelper.Find(g)).ToList();
 
 
         if (!members.Any())
         if (!members.Any())
             return ExecutionState.Error;
             return ExecutionState.Error;
@@ -221,13 +219,6 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
             memberCorners.Clear();
             memberCorners.Clear();
             isInProgress = false;
             isInProgress = false;
         }
         }
-
-        internals.ActionAccumulator.AddActions(new InvokeAction_PassthroughAction(() =>
-        {
-            List<IStructureMemberHandler> members = memberGuids.Select(g => document!.StructureHelper.Find(g))
-                .Where(x => x is ILayerHandler).Distinct().ToList();
-            SelectMembers(members);
-        }));
     }
     }
 
 
     public bool IsTransforming => isInProgress;
     public bool IsTransforming => isInProgress;

+ 0 - 1
src/PixiEditor/Models/Handlers/Tools/IMoveToolHandler.cs

@@ -2,7 +2,6 @@
 
 
 internal interface IMoveToolHandler : IToolHandler
 internal interface IMoveToolHandler : IToolHandler
 {
 {
-    public bool MoveAllLayers { get; }
     public bool KeepOriginalImage { get; }
     public bool KeepOriginalImage { get; }
     public bool TransformingSelectedArea { get; set; }
     public bool TransformingSelectedArea { get; set; }
 }
 }

+ 7 - 1
src/PixiEditor/ViewModels/SubViewModels/NodeGraphManagerViewModel.cs

@@ -61,8 +61,14 @@ internal class NodeGraphManagerViewModel : SubViewModel<ViewModelMain>
     }
     }
     
     
     [Command.Internal("PixiEditor.NodeGraph.ConnectProperties")]
     [Command.Internal("PixiEditor.NodeGraph.ConnectProperties")]
-    public void ConnectProperties((INodePropertyHandler input, INodePropertyHandler output) args)
+    public void ConnectProperties((INodePropertyHandler input, INodePropertyHandler output, INodePropertyHandler? inputToDisconnect) args)
     {
     {
+        using var changeBlock = Owner.DocumentManagerSubViewModel.ActiveDocument.Operations.StartChangeBlock();
+        if (args.inputToDisconnect != null)
+        {
+            Owner.DocumentManagerSubViewModel.ActiveDocument.NodeGraph.ConnectProperties(args.inputToDisconnect, null);
+        }
+        
         Owner.DocumentManagerSubViewModel.ActiveDocument?.NodeGraph.ConnectProperties(args.input, args.output);
         Owner.DocumentManagerSubViewModel.ActiveDocument?.NodeGraph.ConnectProperties(args.input, args.output);
     }
     }
 
 

+ 13 - 17
src/PixiEditor/ViewModels/Tools/Tools/MoveToolViewModel.cs

@@ -21,7 +21,6 @@ internal class MoveToolViewModel : ToolViewModel, IMoveToolHandler
 
 
     private string transformingActionDisplay = "MOVE_TOOL_ACTION_DISPLAY_TRANSFORMING";
     private string transformingActionDisplay = "MOVE_TOOL_ACTION_DISPLAY_TRANSFORMING";
     private bool transformingSelectedArea = false;
     private bool transformingSelectedArea = false;
-    public bool MoveAllLayers { get; set; }
 
 
     public override string DefaultIcon => PixiPerfectIcons.MousePointer;
     public override string DefaultIcon => PixiPerfectIcons.MousePointer;
 
 
@@ -35,7 +34,13 @@ internal class MoveToolViewModel : ToolViewModel, IMoveToolHandler
     public override LocalizedString Tooltip => new LocalizedString("MOVE_TOOL_TOOLTIP", Shortcut);
     public override LocalizedString Tooltip => new LocalizedString("MOVE_TOOL_TOOLTIP", Shortcut);
 
 
     [Settings.Bool("KEEP_ORIGINAL_IMAGE_SETTING", Notify = nameof(KeepOriginalChanged))]
     [Settings.Bool("KEEP_ORIGINAL_IMAGE_SETTING", Notify = nameof(KeepOriginalChanged))]
-    public bool KeepOriginalImage => GetValue<bool>();
+    public bool KeepOriginalImage
+    {
+        get
+        {
+            return GetValue<bool>();
+        }
+    }
 
 
     public override BrushShape BrushShape => BrushShape.Hidden;
     public override BrushShape BrushShape => BrushShape.Hidden;
     public override Type[]? SupportedLayerTypes { get; } = null;
     public override Type[]? SupportedLayerTypes { get; } = null;
@@ -59,21 +64,7 @@ internal class MoveToolViewModel : ToolViewModel, IMoveToolHandler
 
 
     public override void ModifierKeyChanged(bool ctrlIsDown, bool shiftIsDown, bool altIsDown)
     public override void ModifierKeyChanged(bool ctrlIsDown, bool shiftIsDown, bool altIsDown)
     {
     {
-        if (TransformingSelectedArea)
-        {
-            return;
-        }
-
-        if (ctrlIsDown)
-        {
-            ActionDisplay = new LocalizedString("MOVE_TOOL_ACTION_DISPLAY_CTRL");
-            MoveAllLayers = true;
-        }
-        else
-        {
-            ActionDisplay = defaultActionDisplay;
-            MoveAllLayers = false;
-        }
+        
     }
     }
 
 
     protected override void OnSelected(bool restoring)
     protected override void OnSelected(bool restoring)
@@ -131,6 +122,11 @@ internal class MoveToolViewModel : ToolViewModel, IMoveToolHandler
     public void KeepOriginalChanged()
     public void KeepOriginalChanged()
     {
     {
         var activeDocument = ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument;
         var activeDocument = ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument;
+        if (activeDocument is null)
+        {
+            return;
+        }
+        
         activeDocument.TransformViewModel.ShowTransformControls = KeepOriginalImage;
         activeDocument.TransformViewModel.ShowTransformControls = KeepOriginalImage;
     }
     }
 }
 }

+ 23 - 10
src/PixiEditor/Views/Nodes/NodeGraphView.cs

@@ -300,7 +300,7 @@ internal class NodeGraphView : Zoombox.Zoombox
             }
             }
         }
         }
     }
     }
-    
+
     private void Node_PropertyChanged(object? sender, PropertyChangedEventArgs e)
     private void Node_PropertyChanged(object? sender, PropertyChangedEventArgs e)
     {
     {
         if (e.PropertyName == nameof(NodeViewModel.PositionBindable))
         if (e.PropertyName == nameof(NodeViewModel.PositionBindable))
@@ -582,11 +582,11 @@ internal class NodeGraphView : Zoombox.Zoombox
 
 
     private void UpdateConnections(NodeView nodeView)
     private void UpdateConnections(NodeView nodeView)
     {
     {
-        if(nodeView == null)
+        if (nodeView == null)
         {
         {
             return;
             return;
         }
         }
-        
+
         foreach (NodePropertyView propertyView in nodeView.GetVisualDescendants().OfType<NodePropertyView>())
         foreach (NodePropertyView propertyView in nodeView.GetVisualDescendants().OfType<NodePropertyView>())
         {
         {
             NodePropertyViewModel property = (NodePropertyViewModel)propertyView.DataContext;
             NodePropertyViewModel property = (NodePropertyViewModel)propertyView.DataContext;
@@ -639,7 +639,7 @@ internal class NodeGraphView : Zoombox.Zoombox
             return;
             return;
         }
         }
 
 
-        (INodePropertyHandler, INodePropertyHandler) connection = (startConnectionProperty, null);
+        (INodePropertyHandler, INodePropertyHandler, INodePropertyHandler?) connection = (startConnectionProperty, null, null);
         if (socket != null)
         if (socket != null)
         {
         {
             endConnectionNode = socket.Node;
             endConnectionNode = socket.Node;
@@ -651,20 +651,33 @@ internal class NodeGraphView : Zoombox.Zoombox
                 return;
                 return;
             }
             }
 
 
-            connection = (startConnectionProperty, endConnectionProperty);
+            connection = (startConnectionProperty, endConnectionProperty, null);
+
+            if (startConnectionProperty.IsInput && endConnectionProperty.IsInput &&
+                startConnectionProperty.ConnectedOutput != null)
+            {
+                connection = (startConnectionProperty.ConnectedOutput, endConnectionProperty, startConnectionProperty);
+            }
 
 
             if (startConnectionNode == endConnectionNode)
             if (startConnectionNode == endConnectionNode)
             {
             {
-                if (_hiddenConnection != null)
+                if (startConnectionProperty != endConnectionProperty)
                 {
                 {
-                    NodeGraph.Connections.Add(_hiddenConnection);
-                    _hiddenConnection = null;
+                    connection = (endConnectionProperty, startConnectionProperty, null);
+                }
+                else
+                {
+                    return;
                 }
                 }
-
-                return;
             }
             }
         }
         }
 
 
+        if (_hiddenConnection != null)
+        {
+            NodeGraph.Connections.Add(_hiddenConnection);
+            _hiddenConnection = null;
+        }
+
         if (ConnectPropertiesCommand != null && ConnectPropertiesCommand.CanExecute(connection))
         if (ConnectPropertiesCommand != null && ConnectPropertiesCommand.CanExecute(connection))
         {
         {
             ConnectPropertiesCommand.Execute(connection);
             ConnectPropertiesCommand.Execute(connection);

+ 1 - 0
src/PixiEditor/Views/Windows/BetaExampleButton.axaml.cs

@@ -72,6 +72,7 @@ public partial class BetaExampleButton : UserControl
         
         
         ViewModelMain.Current.FileSubViewModel.OpenRecoveredDotPixi(null, bytes);
         ViewModelMain.Current.FileSubViewModel.OpenRecoveredDotPixi(null, bytes);
         ViewModelMain.Current.DocumentManagerSubViewModel.Documents[^1].Operations.UseSrgbProcessing();
         ViewModelMain.Current.DocumentManagerSubViewModel.Documents[^1].Operations.UseSrgbProcessing();
+        ViewModelMain.Current.DocumentManagerSubViewModel.Documents[^1].Operations.ClearUndo();
         Analytics.SendOpenExample(FileName);
         Analytics.SendOpenExample(FileName);
     }
     }