Browse Source

Added isexposed to blackboard

Krzysztof Krysiński 3 weeks ago
parent
commit
f318c91ea6

+ 6 - 0
src/PixiEditor.ChangeableDocument/ChangeInfos/NodeGraph/Blackboard/BlackboardVariableExposed_ChangeInfo.cs

@@ -0,0 +1,6 @@
+namespace PixiEditor.ChangeableDocument.ChangeInfos.NodeGraph.Blackboard;
+
+public record BlackboardVariableExposed_ChangeInfo(string VariableName, bool Value) : IChangeInfo
+{
+
+}

+ 5 - 2
src/PixiEditor.ChangeableDocument/Changeables/Graph/Blackboard.cs

@@ -10,7 +10,7 @@ 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)
+    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))
         {
         {
@@ -20,10 +20,11 @@ public class Blackboard : IReadOnlyBlackboard
             variables[name].Unit = unit;
             variables[name].Unit = unit;
             variables[name].Min = min;
             variables[name].Min = min;
             variables[name].Max = max;
             variables[name].Max = max;
+            variables[name].IsExposed = isExposed;
         }
         }
         else
         else
         {
         {
-            variables[name] = new Variable { Type = type, Value = value, Name = name, Unit = unit, Min = min, Max = max };
+            variables[name] = new Variable { Type = type, Value = value, Name = name, Unit = unit, Min = min, Max = max, IsExposed = isExposed };
         }
         }
     }
     }
 
 
@@ -90,6 +91,7 @@ public class Variable : IReadOnlyVariable
     public string? Unit { get; set; }
     public string? Unit { get; set; }
     public double? Min { get; set; }
     public double? Min { get; set; }
     public double? Max { get; set; }
     public double? Max { get; set; }
+    public bool IsExposed { get; set; } = true;
 }
 }
 
 
 public interface IReadOnlyVariable
 public interface IReadOnlyVariable
@@ -100,4 +102,5 @@ public interface IReadOnlyVariable
     public string? Unit { get; }
     public string? Unit { get; }
     public double? Min { get; }
     public double? Min { get; }
     public double? Max { get; }
     public double? Max { get; }
+    public bool IsExposed { get; }
 }
 }

+ 3 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/NestedDocumentNode.cs

@@ -130,6 +130,9 @@ public class NestedDocumentNode : LayerNode, IInputDependentOutputs, ITransforma
                     x.InternalPropertyName == variable.Key && x.ValueType == variable.Value.Type))
                     x.InternalPropertyName == variable.Key && x.ValueType == variable.Value.Type))
                 continue;
                 continue;
 
 
+            if(!variable.Value.IsExposed)
+                continue;
+
             AddInputProperty(new InputProperty(this, variable.Key, variable.Key, variable.Value.Value,
             AddInputProperty(new InputProperty(this, variable.Key, variable.Key, variable.Value.Value,
                 variable.Value.Type));
                 variable.Value.Type));
         }
         }

+ 42 - 0
src/PixiEditor.ChangeableDocument/Changes/NodeGraph/Blackboard/SetBlackboardVariableExposed_Change.cs

@@ -0,0 +1,42 @@
+using PixiEditor.ChangeableDocument.ChangeInfos.NodeGraph.Blackboard;
+
+namespace PixiEditor.ChangeableDocument.Changes.NodeGraph.Blackboard;
+
+internal class SetBlackboardVariableExposed_Change : Change
+{
+    private readonly string variableName;
+    private readonly bool isExposed;
+    private bool wasExposed;
+
+    [GenerateMakeChangeAction]
+    public SetBlackboardVariableExposed_Change(string variableName, bool isExposed)
+    {
+        this.variableName = variableName;
+        this.isExposed = isExposed;
+    }
+
+    public override bool InitializeAndValidate(Document target)
+    {
+        var variable = target.NodeGraph.Blackboard.Variables.FirstOrDefault(v => v.Key == variableName);
+        if (variable.Value == null)
+            return false;
+
+        wasExposed = variable.Value.IsExposed;
+        return true;
+    }
+
+    public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, bool firstApply, out bool ignoreInUndo)
+    {
+        var variable = target.NodeGraph.Blackboard.Variables[variableName];
+        variable.IsExposed = isExposed;
+        ignoreInUndo = false;
+        return new BlackboardVariableExposed_ChangeInfo(variableName, isExposed);
+    }
+
+    public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
+    {
+        var variable = target.NodeGraph.Blackboard.Variables[variableName];
+        variable.IsExposed = wasExposed;
+        return new BlackboardVariableExposed_ChangeInfo(variableName, wasExposed);
+    }
+}

+ 6 - 4
src/PixiEditor.ChangeableDocument/Changes/NodeGraph/Blackboard/SetBlackboardVariable_Change.cs

@@ -17,15 +17,17 @@ internal class SetBlackboardVariable_Change : Change
     private double min;
     private double min;
     private double max;
     private double max;
     private string unit;
     private string unit;
+    private bool isExposed;
 
 
     [GenerateMakeChangeAction]
     [GenerateMakeChangeAction]
-    public SetBlackboardVariable_Change(string variable, object value, double min, double max, string unit)
+    public SetBlackboardVariable_Change(string variable, object value, double min, double max, string unit, bool isExposed)
     {
     {
         this.variable = variable;
         this.variable = variable;
         this.value = value;
         this.value = value;
         this.min = min;
         this.min = min;
         this.max = max;
         this.max = max;
         this.unit = unit;
         this.unit = unit;
+        this.isExposed = isExposed;
     }
     }
 
 
     public override bool InitializeAndValidate(Document target)
     public override bool InitializeAndValidate(Document target)
@@ -81,9 +83,9 @@ internal class SetBlackboardVariable_Change : Change
         if (target.NodeGraph.Blackboard.GetVariable(variable) == null)
         if (target.NodeGraph.Blackboard.GetVariable(variable) == null)
         {
         {
             Type type = value.GetType();
             Type type = value.GetType();
-            target.NodeGraph.Blackboard.SetVariable(variable, type, value, unit, min, max);
+            target.NodeGraph.Blackboard.SetVariable(variable, type, value, unit, min, max, isExposed);
             InformBlackboardAccessingNodes(target, variable);
             InformBlackboardAccessingNodes(target, variable);
-            return new BlackboardVariable_ChangeInfo(variable, value.GetType(), value, min, max, unit);
+            return new List<IChangeInfo>() {new BlackboardVariable_ChangeInfo(variable, value.GetType(), value, min, max, unit), new BlackboardVariableExposed_ChangeInfo(variable, isExposed)};
         }
         }
 
 
         var oldVar = target.NodeGraph.Blackboard.Variables[variable];
         var oldVar = target.NodeGraph.Blackboard.Variables[variable];
@@ -105,7 +107,7 @@ internal class SetBlackboardVariable_Change : Change
         var currentVar = target.NodeGraph.Blackboard.Variables[variable];
         var currentVar = target.NodeGraph.Blackboard.Variables[variable];
         target.NodeGraph.Blackboard.SetVariable(variable, currentVar.Type, originalValue!);
         target.NodeGraph.Blackboard.SetVariable(variable, currentVar.Type, originalValue!);
         InformBlackboardAccessingNodes(target, variable);
         InformBlackboardAccessingNodes(target, variable);
-        return new BlackboardVariable_ChangeInfo(variable, currentVar.Type, currentVar.Value, currentVar.Min ?? double.MinValue, currentVar.Max ?? double.MaxValue, currentVar.Unit);
+        return new List<IChangeInfo>() {new BlackboardVariable_ChangeInfo(variable, currentVar.Type, currentVar.Value, currentVar.Min ?? double.MinValue, currentVar.Max ?? double.MaxValue, currentVar.Unit), new BlackboardVariableExposed_ChangeInfo(variable, currentVar.IsExposed)};
     }
     }
 
 
     private void InformBlackboardAccessingNodes(Document target, string variableName)
     private void InformBlackboardAccessingNodes(Document target, string variableName)

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

@@ -1255,5 +1255,6 @@
   "TO_SMART_LAYER": "To Smart Layer",
   "TO_SMART_LAYER": "To Smart Layer",
   "PLACE_ELEMENT": "Place Element",
   "PLACE_ELEMENT": "Place Element",
   "PLACE_ELEMENT_DESCRIPTIVE": "Place an external image or document as a new layer",
   "PLACE_ELEMENT_DESCRIPTIVE": "Place an external image or document as a new layer",
-  "FAILED_TO_PLACE_ELEMENT": "Failed to place element: {0}"
+  "FAILED_TO_PLACE_ELEMENT": "Failed to place element: {0}",
+  "EXPOSE_VARIABLE_TOOLTIP": "Expose variable outside of the graph (Brush toolbar setting, Nested Node Input)"
 }
 }

+ 5 - 2
src/PixiEditor/Helpers/DocumentViewModelBuilder.cs

@@ -550,7 +550,8 @@ internal class NodeGraphBuilder
     {
     {
         public List<VariableBuilder> Variables { get; set; } = new List<VariableBuilder>();
         public List<VariableBuilder> Variables { get; set; } = new List<VariableBuilder>();
 
 
-        public BlackboardBuilder WithVariable(string name, object value, string unit = null, double? min = null, double? max = null)
+        public BlackboardBuilder WithVariable(string name, object value, string unit = null, double? min = null,
+            double? max = null, bool isExposed = true)
         {
         {
             Variables.Add(new VariableBuilder
             Variables.Add(new VariableBuilder
             {
             {
@@ -558,7 +559,8 @@ internal class NodeGraphBuilder
                 Value = value,
                 Value = value,
                 Unit = unit,
                 Unit = unit,
                 Min = min,
                 Min = min,
-                Max = max
+                Max = max,
+                IsExposed = isExposed
             });
             });
 
 
             return this;
             return this;
@@ -572,5 +574,6 @@ internal class NodeGraphBuilder
         public string Unit { get; set; }
         public string Unit { get; set; }
         public double? Min { get; set; }
         public double? Min { get; set; }
         public double? Max { get; set; }
         public double? Max { get; set; }
+        public bool IsExposed { get; set; }
     }
     }
 }
 }

+ 1 - 1
src/PixiEditor/Helpers/Extensions/PixiParserDocumentEx.cs

@@ -68,7 +68,7 @@ internal static class PixiParserDocumentEx
                 {
                 {
                     foreach (var kvp in graph.Blackboard.Variables)
                     foreach (var kvp in graph.Blackboard.Variables)
                     {
                     {
-                        x.WithVariable(kvp.Name, kvp.Value, kvp.Unit, kvp.Min, kvp.Max);
+                        x.WithVariable(kvp.Name, kvp.Value, kvp.Unit, kvp.Min, kvp.Max, kvp.IsExposed);
                     }
                     }
                 });
                 });
             }
             }

+ 11 - 0
src/PixiEditor/Models/Controllers/BrushLibrary.cs

@@ -21,6 +21,7 @@ internal class BrushLibrary
     public event Action BrushesChanged;
     public event Action BrushesChanged;
 
 
     private FileSystemWatcher brushWatcher;
     private FileSystemWatcher brushWatcher;
+    private HashSet<string> brushesBeingLoaded = new();
 
 
     public BrushLibrary(string pathToBrushes)
     public BrushLibrary(string pathToBrushes)
     {
     {
@@ -86,6 +87,12 @@ internal class BrushLibrary
 
 
     private void OnBrushChanged(object sender, FileSystemEventArgs e)
     private void OnBrushChanged(object sender, FileSystemEventArgs e)
     {
     {
+        if (!brushesBeingLoaded.Add(e.FullPath))
+        {
+            // Prevent multiple change events from causing multiple reloads
+            return;
+        }
+
         Dispatcher.UIThread.Post(() =>
         Dispatcher.UIThread.Post(() =>
         {
         {
             try
             try
@@ -112,6 +119,10 @@ internal class BrushLibrary
             {
             {
                 Console.WriteLine($"Failed to reload brush from {e.FullPath}: {ex.Message}");
                 Console.WriteLine($"Failed to reload brush from {e.FullPath}: {ex.Message}");
             }
             }
+            finally
+            {
+                brushesBeingLoaded.Remove(e.FullPath);
+            }
         });
         });
     }
     }
 
 

+ 18 - 5
src/PixiEditor/Models/DocumentModels/DocumentUpdater.cs

@@ -260,6 +260,9 @@ internal class DocumentUpdater
             case NestedDocumentLink_ChangeInfo info:
             case NestedDocumentLink_ChangeInfo info:
                 ProcessNestedDocumentLinkChangeInfo(info);
                 ProcessNestedDocumentLinkChangeInfo(info);
                 break;
                 break;
+            case BlackboardVariableExposed_ChangeInfo info:
+                ProcessBlackboardVariableExposedChangeInfo(info);
+                break;
         }
         }
     }
     }
 
 
@@ -1007,11 +1010,7 @@ internal class DocumentUpdater
         if (node is BrushOutputNodeViewModel brushVm)
         if (node is BrushOutputNodeViewModel brushVm)
         {
         {
             ViewModelMain.Current.BrushesSubViewModel.BrushLibrary.Add(
             ViewModelMain.Current.BrushesSubViewModel.BrushLibrary.Add(
-                new Brush(name, doc, "OPENED_DOCUMENT", null)
-                {
-                    IsReadOnly = true,
-                    IsDuplicable = false
-                });
+                new Brush(name, doc, "OPENED_DOCUMENT", null) { IsReadOnly = true, IsDuplicable = false });
         }
         }
     }
     }
 
 
@@ -1089,4 +1088,18 @@ internal class DocumentUpdater
         node.SetReferenceId(info.ReferenceId);
         node.SetReferenceId(info.ReferenceId);
         node.UpdateLinkedStatus();
         node.UpdateLinkedStatus();
     }
     }
+
+    private void ProcessBlackboardVariableExposedChangeInfo(BlackboardVariableExposed_ChangeInfo info)
+    {
+        var existingVar = doc.NodeGraphHandler.Blackboard.GetVariable(info.VariableName);
+        if (existingVar == null)
+        {
+            return;
+        }
+
+        if (existingVar is VariableViewModel varVm)
+        {
+            varVm.SetIsExposedInternal(info.Value);
+        }
+    }
 }
 }

+ 22 - 2
src/PixiEditor/ViewModels/Document/Blackboard/VariableViewModel.cs

@@ -22,6 +22,7 @@ internal class VariableViewModel : ViewModelBase, IVariableHandler
     private Type type;
     private Type type;
     private object value;
     private object value;
     private string name;
     private string name;
+    private bool isExposed = true;
 
 
     public Type Type
     public Type Type
     {
     {
@@ -50,6 +51,19 @@ internal class VariableViewModel : ViewModelBase, IVariableHandler
     private DocumentInternalParts internals { get; }
     private DocumentInternalParts internals { get; }
     public ICommand RemoveCommand { get; }
     public ICommand RemoveCommand { get; }
 
 
+    public bool IsExposedBindable
+    {
+        get => isExposed;
+        set
+        {
+            if (value != IsExposedBindable)
+            {
+                internals.ActionAccumulator.AddFinishedActions(
+                    new SetBlackboardVariableExposed_Action(Name, value));
+            }
+        }
+    }
+
     public VariableViewModel(string name, Type type, object value, string? unit, double min, double max,
     public VariableViewModel(string name, Type type, object value, string? unit, double min, double max,
         DocumentInternalParts internals)
         DocumentInternalParts internals)
     {
     {
@@ -69,7 +83,7 @@ internal class VariableViewModel : ViewModelBase, IVariableHandler
                 return;
                 return;
 
 
             internals.ActionAccumulator.AddFinishedActions(
             internals.ActionAccumulator.AddFinishedActions(
-                new SetBlackboardVariable_Action(Name, AdjustValueForBlackboard(SettingView.Value), min, max, unit));
+                new SetBlackboardVariable_Action(Name, AdjustValueForBlackboard(SettingView.Value), min, max, unit, IsExposedBindable));
         };
         };
 
 
         RemoveCommand = new RelayCommand(() =>
         RemoveCommand = new RelayCommand(() =>
@@ -171,11 +185,17 @@ internal class VariableViewModel : ViewModelBase, IVariableHandler
         suppressValueChange = false;
         suppressValueChange = false;
     }
     }
 
 
-    public void SetNameInternal(string newName)
+    internal void SetNameInternal(string newName)
     {
     {
         name = newName;
         name = newName;
 
 
         SettingView.Label = newName;
         SettingView.Label = newName;
         OnPropertyChanged(nameof(Name));
         OnPropertyChanged(nameof(Name));
     }
     }
+
+    internal void SetIsExposedInternal(bool infoValue)
+    {
+        isExposed = infoValue;
+        OnPropertyChanged(nameof(IsExposedBindable));
+    }
 }
 }

+ 1 - 0
src/PixiEditor/ViewModels/Document/DocumentViewModel.Serialization.cs

@@ -585,6 +585,7 @@ internal partial class DocumentViewModel
                 Unit = prop.Value.Unit,
                 Unit = prop.Value.Unit,
                 Min = prop.Value.Min,
                 Min = prop.Value.Min,
                 Max = prop.Value.Max,
                 Max = prop.Value.Max,
+                IsExposed = prop.Value.IsExposed
             });
             });
         }
         }
 
 

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

@@ -436,7 +436,7 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
                     SerializationUtil.Deserialize(varBuilder.Value, config, allFactories, serializerData);
                     SerializationUtil.Deserialize(varBuilder.Value, config, allFactories, serializerData);
                 acc.AddActions(new SetBlackboardVariable_Action(varBuilder.Name, value,
                 acc.AddActions(new SetBlackboardVariable_Action(varBuilder.Name, value,
                     varBuilder.Min ?? double.MinValue,
                     varBuilder.Min ?? double.MinValue,
-                    varBuilder.Max ?? double.MaxValue, varBuilder.Unit));
+                    varBuilder.Max ?? double.MaxValue, varBuilder.Unit, varBuilder.IsExposed));
             }
             }
         }
         }
 
 

+ 1 - 1
src/PixiEditor/ViewModels/Tools/Tools/BrushBasedToolViewModel.cs

@@ -163,7 +163,7 @@ internal class BrushBasedToolViewModel : ToolViewModel, IBrushToolHandler
 
 
         foreach (var blackboardVariable in blackboard.Variables)
         foreach (var blackboardVariable in blackboard.Variables)
         {
         {
-            if (blackboardVariable is VariableViewModel varVm)
+            if (blackboardVariable is VariableViewModel { IsExposedBindable: true } varVm)
             {
             {
                 Toolbar.AddSetting(varVm.SettingView);
                 Toolbar.AddSetting(varVm.SettingView);
                 brushShapeSettings.Add(varVm.SettingView);
                 brushShapeSettings.Add(varVm.SettingView);

+ 28 - 18
src/PixiEditor/Views/Blackboard/VariableView.axaml

@@ -12,30 +12,40 @@
         <blackboard:VariableViewModel />
         <blackboard:VariableViewModel />
     </Design.DataContext>
     </Design.DataContext>
 
 
-    <Grid ColumnDefinitions="Auto,*,Auto">
+    <Grid ColumnDefinitions="Auto,*,Auto, Auto">
         <Grid.Styles>
         <Grid.Styles>
             <Style Selector="input|EditableTextBlock Border">
             <Style Selector="input|EditableTextBlock Border">
-                <Setter Property="Background" Value="{DynamicResource GlyphBrush}"/>
-                <Setter Property="HorizontalAlignment" Value="Left"/>
-                <Setter Property="Padding" Value="5"/>
-                <Setter Property="CornerRadius" Value="{DynamicResource ControlCornerRadius}"/>
-                <Setter Property="Cursor" Value="Hand"/>
+                <Setter Property="Background" Value="{DynamicResource GlyphBrush}" />
+                <Setter Property="HorizontalAlignment" Value="Left" />
+                <Setter Property="Padding" Value="5" />
+                <Setter Property="CornerRadius" Value="{DynamicResource ControlCornerRadius}" />
+                <Setter Property="Cursor" Value="Hand" />
             </Style>
             </Style>
         </Grid.Styles>
         </Grid.Styles>
-            <input:EditableTextBlock Grid.Column="0" Margin="0,0, 10,0"
-                                     Text="{Binding Name, Mode=TwoWay}"
-                                     MinWidth="50"
-                                     Name="name">
-                <input:EditableTextBlock.ContextMenu>
-                    <ContextMenu>
-                        <MenuItem localization:Translator.Key="RENAME"
-                                  Command="{Binding ElementName=name, Path=EnableEditing}"/>
-                    </ContextMenu>
-                </input:EditableTextBlock.ContextMenu>
-            </input:EditableTextBlock>
-        <ContentControl Grid.Column="1" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Content="{Binding SettingView}" />
+        <input:EditableTextBlock Grid.Column="0" Margin="0,0, 10,0"
+                                 Text="{Binding Name, Mode=TwoWay}"
+                                 MinWidth="50"
+                                 Name="name">
+            <input:EditableTextBlock.ContextMenu>
+                <ContextMenu>
+                    <MenuItem localization:Translator.Key="RENAME"
+                              Command="{Binding ElementName=name, Path=EnableEditing}" />
+                </ContextMenu>
+            </input:EditableTextBlock.ContextMenu>
+        </input:EditableTextBlock>
+        <ContentControl Grid.Column="1" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
+                        Content="{Binding SettingView}" />
         <Button Grid.Column="2" Classes="pixi-icon"
         <Button Grid.Column="2" Classes="pixi-icon"
                 Content="{DynamicResource icon-trash}"
                 Content="{DynamicResource icon-trash}"
                 Margin="10,0,0,0" Command="{Binding RemoveCommand}" />
                 Margin="10,0,0,0" Command="{Binding RemoveCommand}" />
+        <CheckBox Grid.Column="3" Classes="ImageCheckBox"
+                  localization:Translator.TooltipKey="EXPOSE_VARIABLE_TOOLTIP"
+                  Margin="10,0,0,0" IsChecked="{Binding IsExposedBindable, Mode=TwoWay}">
+            <CheckBox.Styles>
+                <Style Selector="TextBlock.pixi-icon">
+                    <Setter Property="FontSize" Value="20" />
+                </Style>
+            </CheckBox.Styles>
+        </CheckBox>
     </Grid>
     </Grid>
 </UserControl>
 </UserControl>

+ 1 - 1
src/PixiParser

@@ -1 +1 @@
-Subproject commit 2739f989739356956916f73fcf984ada317747b0
+Subproject commit f45efae128ed15719a2e0d083a3e74bc96b23fd9