Browse Source

Implemented node inputs

CPKreuz 1 year ago
parent
commit
9df24dfe4c

+ 11 - 0
src/PixiEditor.AvaloniaUI/Models/DocumentModels/DocumentUpdater.cs

@@ -185,6 +185,9 @@ internal class DocumentUpdater
             case NodePosition_ChangeInfo info:
                 ProcessNodePosition(info);
                 break;
+            case PropertyValueUpdated_ChangeInfo info:
+                ProcessNodePropertyValueUpdated(info);
+                break;
         }
     }
 
@@ -569,4 +572,12 @@ internal class DocumentUpdater
         NodeViewModel node = doc.StructureHelper.FindNode<NodeViewModel>(info.NodeId);
         node.SetPosition(info.NewPosition);
     }
+    
+    private void ProcessNodePropertyValueUpdated(PropertyValueUpdated_ChangeInfo info)
+    {
+        NodeViewModel node = doc.StructureHelper.FindNode<NodeViewModel>(info.NodeId);
+        var property = node.FindInputProperty(info.Property);
+        
+        property.InternalSetValue(info.Value);
+    }
 }

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

@@ -3,6 +3,7 @@ using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
 using PixiEditor.AvaloniaUI.Models.DocumentPassthroughActions;
 using PixiEditor.ChangeableDocument;
+using PixiEditor.ChangeableDocument.Actions.Generated;
 using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using PixiEditor.ChangeableDocument.ChangeInfos;
@@ -131,6 +132,10 @@ internal class AffectedAreasGatherer
                     AddWholeCanvasToMainImage();
                     AddWholeCanvasToEveryImagePreview();
                     break;
+                case PropertyValueUpdated_ChangeInfo:
+                    AddWholeCanvasToMainImage();
+                    AddWholeCanvasToEveryImagePreview();
+                    break;
             }
         }
     }

+ 1 - 1
src/PixiEditor.AvaloniaUI/Styles/Templates/NodePropertyViewTemplate.axaml

@@ -18,7 +18,7 @@
                             <x:Boolean>True</x:Boolean>
                         </properties:NodeSocket.IsInput>
                     </properties:NodeSocket>
-                    <ContentPresenter Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" Content="{TemplateBinding Content}" />
+                    <ContentPresenter Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" VerticalAlignment="Top" Content="{TemplateBinding Content}" />
                     <properties:NodeSocket Grid.Column="2" Name="PART_OutputSocket"
                                            Label="{Binding DataContext.DisplayName, RelativeSource={RelativeSource TemplatedParent}}"
                                            HorizontalAlignment="Right"

+ 5 - 0
src/PixiEditor.AvaloniaUI/ViewModels/Document/NodeGraphViewModel.cs

@@ -175,6 +175,11 @@ internal class NodeGraphViewModel : ViewModelBase, INodeGraphHandler
         Internals.ActionAccumulator.AddActions(new NodePosition_Action(node.Id, newPos));
     }
 
+    public void UpdatePropertyValue(INodeHandler node, string property, object? value)
+    {
+        Internals.ActionAccumulator.AddFinishedActions(new UpdatePropertyValue_Action(node.Id, property, value));
+    }
+    
     public void EndChangeNodePosition()
     {
         Internals.ActionAccumulator.AddFinishedActions(new EndNodePosition_Action());

+ 20 - 8
src/PixiEditor.AvaloniaUI/ViewModels/Nodes/NodePropertyViewModel.cs

@@ -12,7 +12,7 @@ internal abstract class NodePropertyViewModel : ViewModelBase, INodePropertyHand
 {
     private string propertyName;
     private string displayName;
-    private object value;
+    private object? _value;
     private INodeHandler node;
     private bool isInput;
     private bool isFunc;
@@ -27,10 +27,16 @@ internal abstract class NodePropertyViewModel : ViewModelBase, INodePropertyHand
         set => SetProperty(ref displayName, value);
     }
     
-    public object Value
+    public object? Value
     {
-        get => value;
-        set => SetProperty(ref value, value);
+        get => _value;
+        set
+        {
+            if (SetProperty(ref _value, value))
+            {
+                ViewModelMain.Current.NodeGraphManager.UpdatePropertyValue((node, PropertyName, value));
+            }
+        }
     }
     
     public bool IsInput
@@ -127,16 +133,22 @@ internal abstract class NodePropertyViewModel : ViewModelBase, INodePropertyHand
         
         return (NodePropertyViewModel)Activator.CreateInstance(viewModelType, node, type);
     }
+
+    public void InternalSetValue(object? value) => SetProperty(ref _value, value);
 }
 
 internal abstract class NodePropertyViewModel<T> : NodePropertyViewModel
 {
-    private T nodeValue;
-    
     public new T Value
     {
-        get => nodeValue;
-        set => SetProperty(ref nodeValue, value);
+        get
+        {
+            if (base.Value == null)
+                return default;
+
+            return (T)base.Value;
+        }
+        set => base.Value = value;
     }
     
     public NodePropertyViewModel(NodeViewModel node, Type valueType) : base(node, valueType)

+ 6 - 0
src/PixiEditor.AvaloniaUI/ViewModels/SubViewModels/NodeGraphManagerViewModel.cs

@@ -33,6 +33,12 @@ internal class NodeGraphManagerViewModel : SubViewModel<ViewModelMain>
     {
         Owner.DocumentManagerSubViewModel.ActiveDocument?.NodeGraph.SetNodePosition(args.node, args.newPos);
     }
+
+    [Command.Internal("PixiEditor.NodeGraph.UpdateValue")]
+    public void UpdatePropertyValue((INodeHandler node, string property, object value) args)
+    {
+        Owner.DocumentManagerSubViewModel.ActiveDocument?.NodeGraph.UpdatePropertyValue(args.node, args.property, args.value);
+    }
     
     [Command.Internal("PixiEditor.NodeGraph.EndChangeNodePos")]
     public void EndChangeNodePos()

+ 1 - 0
src/PixiEditor.AvaloniaUI/Views/Nodes/Properties/GenericPropertyView.axaml

@@ -9,6 +9,7 @@
              x:Class="PixiEditor.AvaloniaUI.Views.Nodes.Properties.GenericPropertyView">
     <Grid>
         <TextBlock
+            VerticalAlignment="Center"
             ui:Translator.Key="{Binding DisplayName}"
             HorizontalAlignment="{Binding IsInput, Converter={converters:BoolToValueConverter FalseValue='Right', TrueValue='Left'}}"/>
     </Grid>

+ 3 - 0
src/PixiEditor.ChangeableDocument/ChangeInfos/NodeGraph/PropertyValueUpdated_ChangeInfo.cs

@@ -0,0 +1,3 @@
+namespace PixiEditor.ChangeableDocument.ChangeInfos.NodeGraph;
+
+public record PropertyValueUpdated_ChangeInfo(Guid NodeId, string Property, object Value) : IChangeInfo;

+ 13 - 2
src/PixiEditor.ChangeableDocument/Changeables/Graph/FieldInputProperty.cs

@@ -3,9 +3,20 @@ using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 
 namespace PixiEditor.ChangeableDocument.Changeables.Graph;
 
-public class FieldInputProperty<T> : InputProperty<Func<FieldContext, T>>
+public class FieldInputProperty<T> : InputProperty<Func<FieldContext, T>>, IFieldInputProperty
 {
-    internal FieldInputProperty(Node node, string internalName, string displayName, Func<FieldContext, T> defaultValue) : base(node, internalName, displayName, defaultValue)
+    private T? constantNonOverrideValue;
+    
+    internal FieldInputProperty(Node node, string internalName, string displayName, T defaultValue) : base(node, internalName, displayName, null)
     {
+        constantNonOverrideValue = defaultValue;
+        NonOverridenValue = _ => constantNonOverrideValue;
+    }
+
+    object? IFieldInputProperty.GetFieldConstantValue() => constantNonOverrideValue;
+
+    void IFieldInputProperty.SetFieldConstantValue(object? value)
+    {
+        constantNonOverrideValue = (T)value;
     }
 }

+ 8 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/IFieldInputProperty.cs

@@ -0,0 +1,8 @@
+namespace PixiEditor.ChangeableDocument.Changeables.Graph;
+
+internal interface IFieldInputProperty
+{
+    object? GetFieldConstantValue();
+    
+    void SetFieldConstantValue(object? value);
+}

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

@@ -21,10 +21,10 @@ public class CombineColorNode : Node
     {
         Color = CreateFieldOutput(nameof(Color), "COLOR", GetColor);
         
-        R = CreateFieldInput("R", "R", _ => 0d);
-        G = CreateFieldInput("G", "G", _ => 0d);
-        B = CreateFieldInput("B", "B", _ => 0d);
-        A = CreateFieldInput("A", "A", _ => 1d);
+        R = CreateFieldInput("R", "R", 0d);
+        G = CreateFieldInput("G", "G", 0d);
+        B = CreateFieldInput("B", "B", 0d);
+        A = CreateFieldInput("A", "A", 0d);
     }
 
     private Color GetColor(FieldContext ctx)

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

@@ -21,7 +21,7 @@ public class ModifyImageRightNode : Node
     public ModifyImageRightNode(ModifyImageLeftNode startNode)
     {
         this.startNode = startNode;
-        Color = CreateFieldInput(nameof(Color), "COLOR", _ => new Color(0, 0, 0, 0));
+        Color = CreateFieldInput(nameof(Color), "COLOR", new Color());
         Output = CreateOutput<Image>(nameof(Output), "OUTPUT", null);
     }
 

+ 2 - 3
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Node.cs

@@ -116,10 +116,9 @@ public abstract class Node : IReadOnlyNode, IDisposable
         }
     }
 
-    protected FieldInputProperty<T> CreateFieldInput<T>(string propName, string displayName,
-        Func<FieldContext, T> defaultFunc)
+    protected FieldInputProperty<T> CreateFieldInput<T>(string propName, string displayName, T defaultValue)
     {
-        var property = new FieldInputProperty<T>(this, propName, displayName, defaultFunc);
+        var property = new FieldInputProperty<T>(this, propName, displayName, defaultValue);
         if (InputProperties.Any(x => x.InternalPropertyName == propName))
         {
             throw new InvalidOperationException($"Input with name {propName} already exists.");

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

@@ -19,7 +19,7 @@ public class SeparateColorNode : Node
 
     public SeparateColorNode()
     {
-        Color = CreateFieldInput(nameof(Color), "COLOR", _ => new Color());
+        Color = CreateFieldInput(nameof(Color), "COLOR", new Color());
         R = CreateFieldOutput(nameof(R), "R", ctx => Color.Value(ctx).R / 255d);
         G = CreateFieldOutput(nameof(G), "G", ctx => Color.Value(ctx).G / 255d);
         B = CreateFieldOutput(nameof(B), "B", ctx => Color.Value(ctx).B / 255d);

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

@@ -17,7 +17,7 @@ public class SeparateVecDNode : Node
     {
         X = CreateFieldOutput("X", "X", ctx => Vector.Value(ctx).X);
         Y = CreateFieldOutput("Y", "Y", ctx => Vector.Value(ctx).Y);
-        Vector = CreateFieldInput("Vector", "VECTOR", _ => new VecD(0, 0));
+        Vector = CreateFieldInput("Vector", "VECTOR", new VecD(0, 0));
     }
 
     protected override Image? OnExecute(KeyFrameTime frameTime)

+ 67 - 0
src/PixiEditor.ChangeableDocument/Changes/NodeGraph/UpdateProperty_Change.cs

@@ -0,0 +1,67 @@
+using PixiEditor.ChangeableDocument.Changeables.Graph;
+using PixiEditor.ChangeableDocument.ChangeInfos.NodeGraph;
+
+namespace PixiEditor.ChangeableDocument.Changes.NodeGraph;
+
+internal class UpdatePropertyValue_Change : Change
+{
+    private readonly Guid _nodeId;
+    private readonly string _propertyName;
+    private readonly object? _value;
+    private object? previousValue;
+    
+    [GenerateMakeChangeAction]
+    public UpdatePropertyValue_Change(Guid nodeId, string property, object? value)
+    {
+        _nodeId = nodeId;
+        _propertyName = property;
+        _value = value;
+    }
+    
+    public override bool InitializeAndValidate(Document target) => true;
+
+    public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, bool firstApply, out bool ignoreInUndo)
+    {
+        var node = target.NodeGraph.Nodes.First(x => x.Id == _nodeId);
+        var property = node.GetInputProperty(_propertyName);
+
+        previousValue = GetValue(property);
+        SetValue(property, _value);
+
+        ignoreInUndo = false;
+        
+        return new PropertyValueUpdated_ChangeInfo(_nodeId, _propertyName, _value);
+    }
+
+    public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
+    {
+        var node = target.NodeGraph.Nodes.First(x => x.Id == _nodeId);
+        var property = node.GetInputProperty(_propertyName);
+        SetValue(property, previousValue);
+        
+        return new PropertyValueUpdated_ChangeInfo(_nodeId, _propertyName, previousValue);
+    }
+
+    private static void SetValue(InputProperty property, object? value)
+    {
+        if (property is IFieldInputProperty fieldInput)
+        {
+            fieldInput.SetFieldConstantValue(value);
+        }
+        else
+        {
+            property.NonOverridenValue = value;
+        }
+    }
+    
+
+    private static object? GetValue(InputProperty property)
+    {
+        if (property is IFieldInputProperty fieldInput)
+        {
+            return fieldInput.GetFieldConstantValue();
+        }
+
+        return property.NonOverridenValue;
+    }
+}