Krzysztof Krysiński 3 тижнів тому
батько
коміт
8dcf9e2ea5

+ 16 - 3
src/PixiEditor.ChangeableDocument/Changeables/Graph/Blackboard.cs

@@ -10,7 +10,8 @@ public class Blackboard : IReadOnlyBlackboard
     IReadOnlyDictionary<string, IReadOnlyVariable> IReadOnlyBlackboard.Variables =>
     IReadOnlyDictionary<string, IReadOnlyVariable> IReadOnlyBlackboard.Variables =>
         variables.ToDictionary(kv => kv.Key, kv => (IReadOnlyVariable)kv.Value);
         variables.ToDictionary(kv => kv.Key, kv => (IReadOnlyVariable)kv.Value);
 
 
-    public void SetVariable(string name, Type type, object value, string? unit = null, double? min = null, double? max = null, bool isExposed = true)
+    public void SetVariable(string name, Type type, object value, string? unit = null, double? min = null,
+        double? max = null, bool isExposed = true)
     {
     {
         if (variables.ContainsKey(name))
         if (variables.ContainsKey(name))
         {
         {
@@ -24,12 +25,24 @@ public class Blackboard : IReadOnlyBlackboard
         }
         }
         else
         else
         {
         {
-            variables[name] = new Variable { Type = type, Value = value, Name = name, Unit = unit, Min = min, Max = max, IsExposed = isExposed };
+            variables[name] = new Variable
+            {
+                Type = type,
+                Value = value,
+                Name = name,
+                Unit = unit,
+                Min = min,
+                Max = max,
+                IsExposed = isExposed
+            };
         }
         }
     }
     }
 
 
     public Variable? GetVariable(string name)
     public Variable? GetVariable(string name)
     {
     {
+        if (name == null)
+            return null;
+
         return variables.GetValueOrDefault(name);
         return variables.GetValueOrDefault(name);
     }
     }
 
 
@@ -64,7 +77,7 @@ public class Blackboard : IReadOnlyBlackboard
             hash.Add(variable.Type);
             hash.Add(variable.Type);
             if (variable.Value != null)
             if (variable.Value != null)
             {
             {
-                if(variable.Value is ICacheable cacheable)
+                if (variable.Value is ICacheable cacheable)
                 {
                 {
                     hash.Add(cacheable.GetCacheHash());
                     hash.Add(cacheable.GetCacheHash());
                 }
                 }

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

@@ -6,12 +6,13 @@ namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 [NodeInfo("BlackboardVariableValue")]
 [NodeInfo("BlackboardVariableValue")]
 public class BlackboardVariableValueNode : Node
 public class BlackboardVariableValueNode : Node
 {
 {
+    public const string NameProperty = "VariableName";
     public InputProperty<string> VariableName { get; }
     public InputProperty<string> VariableName { get; }
     public OutputProperty<object> Value { get; }
     public OutputProperty<object> Value { get; }
 
 
     public BlackboardVariableValueNode()
     public BlackboardVariableValueNode()
     {
     {
-        VariableName = CreateInput("VariableName", "VARIABLE_NAME", string.Empty);
+        VariableName = CreateInput(NameProperty, "VARIABLE_NAME", string.Empty);
         Value = CreateOutput<object>("Value", "VALUE", null);
         Value = CreateOutput<object>("Value", "VALUE", null);
     }
     }
 
 

+ 28 - 3
src/PixiEditor.ChangeableDocument/Changes/NodeGraph/Blackboard/RenameBlackboardVariable_Change.cs

@@ -1,4 +1,6 @@
-using PixiEditor.ChangeableDocument.ChangeInfos.NodeGraph.Blackboard;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
+using PixiEditor.ChangeableDocument.ChangeInfos.NodeGraph;
+using PixiEditor.ChangeableDocument.ChangeInfos.NodeGraph.Blackboard;
 
 
 namespace PixiEditor.ChangeableDocument.Changes.NodeGraph.Blackboard;
 namespace PixiEditor.ChangeableDocument.Changes.NodeGraph.Blackboard;
 
 
@@ -29,14 +31,37 @@ internal class RenameBlackboardVariable_Change : Change
         out bool ignoreInUndo)
         out bool ignoreInUndo)
     {
     {
         target.NodeGraph.Blackboard.RenameVariable(oldName, newName);
         target.NodeGraph.Blackboard.RenameVariable(oldName, newName);
+        var changes = UpdateReferences(target.NodeGraph, oldName, newName);
         ignoreInUndo = false;
         ignoreInUndo = false;
 
 
-        return new RenameBlackboardVariable_ChangeInfo(oldName, newName);
+        changes.Insert(0, new RenameBlackboardVariable_ChangeInfo(oldName, newName));
+
+        return changes;
     }
     }
 
 
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
     {
     {
         target.NodeGraph.Blackboard.RenameVariable(newName, oldName);
         target.NodeGraph.Blackboard.RenameVariable(newName, oldName);
-        return new RenameBlackboardVariable_ChangeInfo(newName, oldName);
+        var changes = UpdateReferences(target.NodeGraph, newName, oldName);
+        changes.Insert(0, new RenameBlackboardVariable_ChangeInfo(newName, oldName));
+        return changes;
+    }
+
+    private List<IChangeInfo> UpdateReferences(Changeables.Graph.NodeGraph nodeGraph, string previous, string next)
+    {
+        var changeInfos = new List<IChangeInfo>();
+        foreach (var node in nodeGraph.Nodes)
+        {
+            if (node is BlackboardVariableValueNode blackboardNode)
+            {
+                if (blackboardNode.VariableName.NonOverridenValue == previous)
+                {
+                    blackboardNode.VariableName.NonOverridenValue = next;
+                    changeInfos.Add(new PropertyValueUpdated_ChangeInfo(blackboardNode.Id, BlackboardVariableValueNode.NameProperty, next));
+                }
+            }
+        }
+
+        return changeInfos;
     }
     }
 }
 }

+ 1 - 10
src/PixiEditor/Models/DocumentModels/DocumentUpdater.cs

@@ -1034,16 +1034,7 @@ internal class DocumentUpdater
 
 
     private void ProcessRenameBlackboardVariable(RenameBlackboardVariable_ChangeInfo info)
     private void ProcessRenameBlackboardVariable(RenameBlackboardVariable_ChangeInfo info)
     {
     {
-        var existingVar = doc.NodeGraphHandler.Blackboard.GetVariable(info.OldName);
-        if (existingVar == null)
-        {
-            return;
-        }
-
-        if (existingVar is VariableViewModel varVm)
-        {
-            varVm.SetNameInternal(info.NewName);
-        }
+        doc.NodeGraphHandler.Blackboard.RenameVariableInternal(info.OldName, info.NewName);
     }
     }
 
 
     private void ProcessRemoveBlackboardVariable(BlackboardVariableRemoved_ChangeInfo info)
     private void ProcessRemoveBlackboardVariable(BlackboardVariableRemoved_ChangeInfo info)

+ 1 - 0
src/PixiEditor/Models/Handlers/IBlackboardHandler.cs

@@ -10,4 +10,5 @@ public interface IBlackboardHandler
     public IVariableHandler GetVariable(string name);
     public IVariableHandler GetVariable(string name);
     public void SetVariableInternal(string name, object value);
     public void SetVariableInternal(string name, object value);
     public void RemoveVariableInternal(string name);
     public void RemoveVariableInternal(string name);
+    void RenameVariableInternal(string oldName, string newName);
 }
 }

+ 16 - 0
src/PixiEditor/ViewModels/Document/Blackboard/BlackboardViewModel.cs

@@ -15,6 +15,10 @@ internal class BlackboardViewModel : ViewModelBase, IBlackboardHandler
 
 
     private DocumentInternalParts internals;
     private DocumentInternalParts internals;
 
 
+    public event Action<string> VariableAdded;
+    public event Action<string> VariableRemoved;
+    public event Action<string, string> VariableRenamed;
+
     public BlackboardViewModel(DocumentInternalParts internals)
     public BlackboardViewModel(DocumentInternalParts internals)
     {
     {
         this.internals = internals;
         this.internals = internals;
@@ -47,6 +51,7 @@ internal class BlackboardViewModel : ViewModelBase, IBlackboardHandler
         double min = double.MinValue, double max = double.MaxValue)
         double min = double.MinValue, double max = double.MaxValue)
     {
     {
         Variables.Add(new VariableViewModel(name, type, value, unit, min, max, internals));
         Variables.Add(new VariableViewModel(name, type, value, unit, min, max, internals));
+        VariableAdded?.Invoke(name);
     }
     }
 
 
     public IVariableHandler? GetVariable(string name)
     public IVariableHandler? GetVariable(string name)
@@ -65,5 +70,16 @@ internal class BlackboardViewModel : ViewModelBase, IBlackboardHandler
         VariableViewModel? variable = Variables.FirstOrDefault(v => v.Name == name);
         VariableViewModel? variable = Variables.FirstOrDefault(v => v.Name == name);
         if (variable != null)
         if (variable != null)
             Variables.Remove(variable);
             Variables.Remove(variable);
+
+        VariableRemoved?.Invoke(name);
+    }
+
+    public void RenameVariableInternal(string oldName, string newName)
+    {
+        VariableViewModel? variable = Variables.FirstOrDefault(v => v.Name == oldName);
+        if (variable != null)
+            variable.SetNameInternal(newName);
+
+        VariableRenamed?.Invoke(oldName, newName);
     }
     }
 }
 }

+ 3 - 1
src/PixiEditor/ViewModels/Document/Blackboard/VariableViewModel.cs

@@ -1,4 +1,5 @@
-using System.Windows.Input;
+using System.Collections.ObjectModel;
+using System.Windows.Input;
 using CommunityToolkit.Mvvm.Input;
 using CommunityToolkit.Mvvm.Input;
 using Drawie.Backend.Core;
 using Drawie.Backend.Core;
 using Drawie.Backend.Core.ColorsImpl;
 using Drawie.Backend.Core.ColorsImpl;
@@ -10,6 +11,7 @@ using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using PixiEditor.Models.BrushEngine;
 using PixiEditor.Models.BrushEngine;
 using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.Handlers;
 using PixiEditor.Models.Handlers;
+using PixiEditor.Parser.Graph;
 using PixiEditor.ViewModels.BrushSystem;
 using PixiEditor.ViewModels.BrushSystem;
 using PixiEditor.ViewModels.Tools.Tools;
 using PixiEditor.ViewModels.Tools.Tools;
 using PixiEditor.ViewModels.Tools.ToolSettings.Settings;
 using PixiEditor.ViewModels.Tools.ToolSettings.Settings;

+ 57 - 2
src/PixiEditor/ViewModels/Document/Nodes/BlackboardVariableValueNodeViewModel.cs

@@ -1,7 +1,62 @@
-using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
+using System.Collections.ObjectModel;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 using PixiEditor.ViewModels.Nodes;
 using PixiEditor.ViewModels.Nodes;
+using PixiEditor.ViewModels.Nodes.Properties;
 
 
 namespace PixiEditor.ViewModels.Document.Nodes;
 namespace PixiEditor.ViewModels.Document.Nodes;
 
 
 [NodeViewModel("BLACKBOARD_VARIABLE_VALUE", null, PixiPerfectIcons.Variable)]
 [NodeViewModel("BLACKBOARD_VARIABLE_VALUE", null, PixiPerfectIcons.Variable)]
-internal class BlackboardVariableValueNodeViewModel : NodeViewModel<BlackboardVariableValueNode>;
+internal class BlackboardVariableValueNodeViewModel : NodeViewModel<BlackboardVariableValueNode>
+{
+    public override void OnInitialized()
+    {
+        Document.NodeGraph.Blackboard.VariableAdded += BlackboardOnVariableAdded;
+        Document.NodeGraph.Blackboard.VariableRemoved += BlackboardOnVariableRemoved;
+        Document.NodeGraph.Blackboard.VariableRenamed += BlackboardOnVariableRenamed;
+
+        if (InputPropertyMap[BlackboardVariableValueNode.NameProperty] is StringPropertyViewModel
+            stringPropertyViewModel)
+        {
+            stringPropertyViewModel.AvailableOptions =
+                new ObservableCollection<string>(Internals.Tracker.Document.Blackboard.Variables.Keys);
+        }
+    }
+
+    private void BlackboardOnVariableAdded(string obj)
+    {
+        if (InputPropertyMap[BlackboardVariableValueNode.NameProperty] is StringPropertyViewModel
+            stringPropertyViewModel)
+        {
+            if (!stringPropertyViewModel.AvailableOptions!.Contains(obj))
+            {
+                stringPropertyViewModel.AvailableOptions?.Add(obj);
+            }
+        }
+    }
+
+    private void BlackboardOnVariableRemoved(string obj)
+    {
+        if (InputPropertyMap[BlackboardVariableValueNode.NameProperty] is StringPropertyViewModel
+            stringPropertyViewModel)
+        {
+            stringPropertyViewModel.AvailableOptions?.Remove(obj);
+        }
+    }
+
+    private void BlackboardOnVariableRenamed(string oldName, string newName)
+    {
+        if (InputPropertyMap[BlackboardVariableValueNode.NameProperty] is StringPropertyViewModel
+            stringPropertyViewModel)
+        {
+            var options = stringPropertyViewModel.AvailableOptions;
+            if (options == null)
+                return;
+
+            var index = options.IndexOf(oldName);
+            if (index >= 0)
+            {
+                options[index] = newName;
+            }
+        }
+    }
+}

+ 3 - 1
src/PixiEditor/ViewModels/Nodes/NodePropertyViewModel.cs

@@ -44,7 +44,7 @@ internal abstract class NodePropertyViewModel : ViewModelBase, INodePropertyHand
         set
         set
         {
         {
             var oldValue = _value;
             var oldValue = _value;
-            if(value == null && oldValue == null) return;
+            if (value == null && oldValue == null) return;
             if (oldValue != null && oldValue.Equals(value)) return;
             if (oldValue != null && oldValue.Equals(value)) return;
 
 
             if (MergeChanges)
             if (MergeChanges)
@@ -114,6 +114,7 @@ internal abstract class NodePropertyViewModel : ViewModelBase, INodePropertyHand
         set => SetProperty(ref isVisible, value);
         set => SetProperty(ref isVisible, value);
     }
     }
 
 
+
     public INodePropertyHandler? ConnectedOutput
     public INodePropertyHandler? ConnectedOutput
     {
     {
         get => connectedOutput;
         get => connectedOutput;
@@ -185,6 +186,7 @@ internal abstract class NodePropertyViewModel : ViewModelBase, INodePropertyHand
         {
         {
             targetType = typeof(Enum);
             targetType = typeof(Enum);
         }
         }
+
         if (Application.Current.Styles.TryGetResource($"{targetType.Name}SocketBrush", App.Current.ActualThemeVariant,
         if (Application.Current.Styles.TryGetResource($"{targetType.Name}SocketBrush", App.Current.ActualThemeVariant,
                 out object brush))
                 out object brush))
         {
         {

+ 28 - 2
src/PixiEditor/ViewModels/Nodes/Properties/StringPropertyViewModel.cs

@@ -1,4 +1,5 @@
-using System.ComponentModel;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices;
 using Avalonia.Interactivity;
 using Avalonia.Interactivity;
 using Avalonia.Threading;
 using Avalonia.Threading;
@@ -14,11 +15,28 @@ namespace PixiEditor.ViewModels.Nodes.Properties;
 
 
 internal class StringPropertyViewModel : NodePropertyViewModel<string>
 internal class StringPropertyViewModel : NodePropertyViewModel<string>
 {
 {
+    private ObservableCollection<string>? availableOptions;
     private string kind = "txt";
     private string kind = "txt";
+
     public string StringValue
     public string StringValue
     {
     {
         get => Value;
         get => Value;
-        set => Value = value;
+        set
+        {
+            Value = value;
+        }
+    }
+
+    public string StringNotNullValue
+    {
+        get => Value ?? string.Empty;
+        set
+        {
+            if (value == null)
+                return;
+
+            Value = value;
+        }
     }
     }
 
 
     public string Kind
     public string Kind
@@ -27,6 +45,13 @@ internal class StringPropertyViewModel : NodePropertyViewModel<string>
         set => SetProperty(ref kind, value);
         set => SetProperty(ref kind, value);
     }
     }
 
 
+    public ObservableCollection<string>? AvailableOptions
+    {
+        get => availableOptions;
+        set => SetProperty(ref availableOptions, value);
+    }
+
+
     public StringPropertyViewModel(NodeViewModel node, Type valueType) : base(node, valueType)
     public StringPropertyViewModel(NodeViewModel node, Type valueType) : base(node, valueType)
     {
     {
         PropertyChanged += StringPropertyViewModel_PropertyChanged;
         PropertyChanged += StringPropertyViewModel_PropertyChanged;
@@ -37,6 +62,7 @@ internal class StringPropertyViewModel : NodePropertyViewModel<string>
         if (e.PropertyName == nameof(Value))
         if (e.PropertyName == nameof(Value))
         {
         {
             OnPropertyChanged(nameof(StringValue));
             OnPropertyChanged(nameof(StringValue));
+            OnPropertyChanged(nameof(StringNotNullValue));
         }
         }
     }
     }
 }
 }

+ 16 - 6
src/PixiEditor/Views/Nodes/Properties/StringPropertyView.axaml

@@ -12,16 +12,26 @@
                              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
                              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
                              x:DataType="properties1:StringPropertyViewModel"
                              x:DataType="properties1:StringPropertyViewModel"
                              x:Class="PixiEditor.Views.Nodes.Properties.StringPropertyView">
                              x:Class="PixiEditor.Views.Nodes.Properties.StringPropertyView">
+    <Design.DataContext>
+        <properties1:StringPropertyViewModel />
+    </Design.DataContext>
     <Grid>
     <Grid>
         <DockPanel LastChildFill="True"
         <DockPanel LastChildFill="True"
                    HorizontalAlignment="{Binding IsInput, Converter={converters:BoolToValueConverter FalseValue='Right', TrueValue='Stretch'}}">
                    HorizontalAlignment="{Binding IsInput, Converter={converters:BoolToValueConverter FalseValue='Right', TrueValue='Stretch'}}">
-            <TextBlock ui:Translator.TooltipKey="{Binding DisplayName}" VerticalAlignment="Center" ui:Translator.Key="{Binding DisplayName}" />
+            <TextBlock ui:Translator.TooltipKey="{Binding DisplayName}" VerticalAlignment="Center"
+                       ui:Translator.Key="{Binding DisplayName}" />
             <Panel IsVisible="{Binding ShowInputField}">
             <Panel IsVisible="{Binding ShowInputField}">
-            <input:StringEditor
-                IsVisible="{Binding IsInput}"
-                Text="{Binding Value, Mode=TwoWay}"
-                ContentKind="{Binding Kind}"
-                Errors="{Binding Errors}"/>
+                <Panel IsVisible="{Binding IsInput}">
+                    <input:StringEditor
+                        IsVisible="{Binding AvailableOptions, Converter={converters:NotNullToVisibilityConverter Inverted=True}}"
+                        Text="{Binding Value, Mode=TwoWay}"
+                        ContentKind="{Binding Kind}"
+                        Errors="{Binding Errors}" />
+                    <ComboBox IsVisible="{Binding AvailableOptions, Converter={converters:NotNullToVisibilityConverter}}"
+                              ItemsSource="{Binding AvailableOptions}"
+                              PointerPressed="InputElement_OnPointerPressed"
+                              SelectedValue="{Binding StringNotNullValue, Mode=TwoWay}"/>
+                </Panel>
             </Panel>
             </Panel>
         </DockPanel>
         </DockPanel>
     </Grid>
     </Grid>

+ 5 - 0
src/PixiEditor/Views/Nodes/Properties/StringPropertyView.axaml.cs

@@ -31,4 +31,9 @@ public partial class StringPropertyView : NodePropertyView
     {
     {
         InitializeComponent();
         InitializeComponent();
     }
     }
+
+    private void InputElement_OnPointerPressed(object? sender, PointerPressedEventArgs e)
+    {
+        e.Handled = true;
+    }
 }
 }