diff --git a/src/Artemis.Core/Artemis.Core.csproj.DotSettings b/src/Artemis.Core/Artemis.Core.csproj.DotSettings
index a18836e5e..c23015925 100644
--- a/src/Artemis.Core/Artemis.Core.csproj.DotSettings
+++ b/src/Artemis.Core/Artemis.Core.csproj.DotSettings
@@ -93,4 +93,6 @@
TrueTrueTrue
- True
\ No newline at end of file
+ True
+ True
+ True
\ No newline at end of file
diff --git a/src/Artemis.Core/DefaultTypes/Properties/ColorGradientLayerProperty.cs b/src/Artemis.Core/DefaultTypes/Properties/ColorGradientLayerProperty.cs
index c88cbd625..b108d81f1 100644
--- a/src/Artemis.Core/DefaultTypes/Properties/ColorGradientLayerProperty.cs
+++ b/src/Artemis.Core/DefaultTypes/Properties/ColorGradientLayerProperty.cs
@@ -1,13 +1,8 @@
-using System.Collections.Specialized;
-using SkiaSharp;
-
-namespace Artemis.Core;
+namespace Artemis.Core;
///
public class ColorGradientLayerProperty : LayerProperty
{
- private ColorGradient? _subscribedGradient;
-
internal ColorGradientLayerProperty()
{
KeyframesSupported = false;
@@ -22,29 +17,6 @@ public class ColorGradientLayerProperty : LayerProperty
return p.CurrentValue;
}
- #region Overrides of LayerProperty
-
- ///
- protected override void OnCurrentValueSet()
- {
- // Don't allow color gradients to be null
- if (BaseValue == null!)
- BaseValue = new ColorGradient(DefaultValue);
-
- if (!ReferenceEquals(_subscribedGradient, BaseValue))
- {
- if (_subscribedGradient != null)
- _subscribedGradient.CollectionChanged -= SubscribedGradientOnPropertyChanged;
- _subscribedGradient = BaseValue;
- _subscribedGradient.CollectionChanged += SubscribedGradientOnPropertyChanged;
- }
-
- CreateDataBindingRegistrations();
- base.OnCurrentValueSet();
- }
-
- #endregion
-
///
protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased)
{
@@ -60,33 +32,12 @@ public class ColorGradientLayerProperty : LayerProperty
if (BaseValue == null!)
BaseValue = new ColorGradient(DefaultValue);
- base.OnInitialize();
+ DataBinding.RegisterDataBindingProperty(() => CurrentValue, value =>
+ {
+ if (value != null)
+ CurrentValue = value;
+ }, "Value");
}
#endregion
-
- private void CreateDataBindingRegistrations()
- {
- DataBinding.ClearDataBindingProperties();
- if (CurrentValue == null!)
- return;
-
- for (int index = 0; index < CurrentValue.Count; index++)
- {
- int stopIndex = index;
-
- void Setter(SKColor value)
- {
- CurrentValue[stopIndex].Color = value;
- }
-
- DataBinding.RegisterDataBindingProperty(() => CurrentValue[stopIndex].Color, Setter, $"Color #{stopIndex + 1}");
- }
- }
-
- private void SubscribedGradientOnPropertyChanged(object? sender, NotifyCollectionChangedEventArgs args)
- {
- if (CurrentValue.Count != DataBinding.Properties.Count)
- CreateDataBindingRegistrations();
- }
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Models/Profile/DataBindings/DataBindingProperty.cs b/src/Artemis.Core/Models/Profile/DataBindings/DataBindingProperty.cs
index 13a5c9e27..81c4b719a 100644
--- a/src/Artemis.Core/Models/Profile/DataBindings/DataBindingProperty.cs
+++ b/src/Artemis.Core/Models/Profile/DataBindings/DataBindingProperty.cs
@@ -35,7 +35,7 @@ public class DataBindingProperty : IDataBindingProperty
}
///
- public void SetValue(object? value)
+ public void SetValue(object value)
{
// Numeric has a bunch of conversion, this seems the cheapest way to use them :)
switch (value)
diff --git a/src/Artemis.Core/Models/Profile/DataBindings/IDataBindingProperty.cs b/src/Artemis.Core/Models/Profile/DataBindings/IDataBindingProperty.cs
index 7d5dc49bd..7e4ce8d06 100644
--- a/src/Artemis.Core/Models/Profile/DataBindings/IDataBindingProperty.cs
+++ b/src/Artemis.Core/Models/Profile/DataBindings/IDataBindingProperty.cs
@@ -27,5 +27,5 @@ public interface IDataBindingProperty
/// Sets the value of the property this registration points to
///
/// A value matching the type of
- void SetValue(object? value);
+ void SetValue(object value);
}
\ No newline at end of file
diff --git a/src/Artemis.Core/VisualScripting/Internal/DataBindingExitNode.cs b/src/Artemis.Core/VisualScripting/Internal/DataBindingExitNode.cs
index 6b4d367f5..7857f533d 100644
--- a/src/Artemis.Core/VisualScripting/Internal/DataBindingExitNode.cs
+++ b/src/Artemis.Core/VisualScripting/Internal/DataBindingExitNode.cs
@@ -23,7 +23,10 @@ internal class DataBindingExitNode : Node, IExitNode
public void ApplyToDataBinding()
{
foreach ((IDataBindingProperty? property, object? pendingValue) in _propertyValues)
- property.SetValue(pendingValue);
+ {
+ if (pendingValue != null)
+ property.SetValue(pendingValue);
+ }
}
public override void Evaluate()
diff --git a/src/Artemis.Core/VisualScripting/Internal/EventConditionEventStartNode.cs b/src/Artemis.Core/VisualScripting/Internal/EventConditionEventStartNode.cs
index f417e8871..14f1e0562 100644
--- a/src/Artemis.Core/VisualScripting/Internal/EventConditionEventStartNode.cs
+++ b/src/Artemis.Core/VisualScripting/Internal/EventConditionEventStartNode.cs
@@ -15,8 +15,7 @@ internal class EventConditionEventStartNode : DefaultNode
public void SetDataModelEvent(IDataModelEvent? dataModelEvent)
{
-
- }
+ }
public void CreatePins(IDataModelEvent? dataModelEvent)
{
diff --git a/src/Artemis.Core/VisualScripting/NodeScript.cs b/src/Artemis.Core/VisualScripting/NodeScript.cs
index 9bfb08011..7a02555ac 100644
--- a/src/Artemis.Core/VisualScripting/NodeScript.cs
+++ b/src/Artemis.Core/VisualScripting/NodeScript.cs
@@ -93,10 +93,8 @@ public abstract class NodeScript : CorePropertyChanged, INodeScript
NodeTypeStore.NodeTypeRemoved += NodeTypeStoreOnNodeTypeRemoved;
if (defaultNodes != null)
- {
foreach (DefaultNode defaultNode in defaultNodes)
AddNode(defaultNode);
- }
}
internal NodeScript(string name, string description, NodeScriptEntity entity, object? context = null, List? defaultNodes = null)
@@ -109,12 +107,10 @@ public abstract class NodeScript : CorePropertyChanged, INodeScript
NodeTypeStore.NodeTypeAdded += NodeTypeStoreOnNodeTypeAdded;
NodeTypeStore.NodeTypeRemoved += NodeTypeStoreOnNodeTypeRemoved;
-
+
if (defaultNodes != null)
- {
foreach (DefaultNode defaultNode in defaultNodes)
AddNode(defaultNode);
- }
}
#endregion
diff --git a/src/Artemis.Core/VisualScripting/CustomNodeViewModel.cs b/src/Artemis.Core/VisualScripting/Nodes/CustomNodeViewModel.cs
similarity index 100%
rename from src/Artemis.Core/VisualScripting/CustomNodeViewModel.cs
rename to src/Artemis.Core/VisualScripting/Nodes/CustomNodeViewModel.cs
diff --git a/src/Artemis.Core/VisualScripting/Nodes/CustomNodeViewModelPosition.cs b/src/Artemis.Core/VisualScripting/Nodes/CustomNodeViewModelPosition.cs
new file mode 100644
index 000000000..74616dd8e
--- /dev/null
+++ b/src/Artemis.Core/VisualScripting/Nodes/CustomNodeViewModelPosition.cs
@@ -0,0 +1,32 @@
+namespace Artemis.Core;
+
+///
+/// Represents the position of a node's custom view model.
+///
+public enum CustomNodeViewModelPosition
+{
+ ///
+ /// Puts the view model above the pins.
+ ///
+ AbovePins,
+
+ ///
+ /// Puts the view model between the pins, vertically aligned to the top.
+ ///
+ BetweenPinsTop,
+
+ ///
+ /// Puts the view model between the pins, vertically aligned to the center.
+ ///
+ BetweenPinsCenter,
+
+ ///
+ /// Puts the view model between the pins, vertically aligned to the bottom.
+ ///
+ BetweenPinsBottom,
+
+ ///
+ /// Puts the view model below the pins.
+ ///
+ BelowPins
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/VisualScripting/DefaultNode.cs b/src/Artemis.Core/VisualScripting/Nodes/DefaultNode.cs
similarity index 100%
rename from src/Artemis.Core/VisualScripting/DefaultNode.cs
rename to src/Artemis.Core/VisualScripting/Nodes/DefaultNode.cs
diff --git a/src/Artemis.Core/VisualScripting/Nodes/ICustomViewModelNode.cs b/src/Artemis.Core/VisualScripting/Nodes/ICustomViewModelNode.cs
new file mode 100644
index 000000000..b16623935
--- /dev/null
+++ b/src/Artemis.Core/VisualScripting/Nodes/ICustomViewModelNode.cs
@@ -0,0 +1,18 @@
+namespace Artemis.Core;
+
+///
+/// Represents a node that has a custom view model.
+///
+public interface ICustomViewModelNode
+{
+ ///
+ /// Gets or sets the position of the node's custom view model.
+ ///
+ CustomNodeViewModelPosition ViewModelPosition { get; }
+
+ ///
+ /// Called whenever the node must show it's custom view model, if , no custom view model is used
+ ///
+ /// The custom view model, if , no custom view model is used
+ ICustomNodeViewModel? GetCustomViewModel(NodeScript nodeScript);
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/VisualScripting/Node.cs b/src/Artemis.Core/VisualScripting/Nodes/Node.cs
similarity index 76%
rename from src/Artemis.Core/VisualScripting/Node.cs
rename to src/Artemis.Core/VisualScripting/Nodes/Node.cs
index f212524de..e451f05aa 100644
--- a/src/Artemis.Core/VisualScripting/Node.cs
+++ b/src/Artemis.Core/VisualScripting/Nodes/Node.cs
@@ -2,10 +2,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
-using System.Reflection;
using Artemis.Core.Events;
-using Ninject;
-using Ninject.Parameters;
namespace Artemis.Core;
@@ -339,7 +336,8 @@ public abstract class Node : BreakableModel, INode
}
///
- /// Called when the node was loaded from storage or newly created, at this point pin connections aren't reestablished yet.
+ /// Called when the node was loaded from storage or newly created, at this point pin connections aren't reestablished
+ /// yet.
///
/// The script the node is contained in
public virtual void Initialize(INodeScript script)
@@ -374,16 +372,6 @@ public abstract class Node : BreakableModel, INode
TryOrBreak(Evaluate, "Failed to evaluate");
}
- ///
- /// Called whenever the node must show it's custom view model, if , no custom view model is used
- ///
- ///
- /// The custom view model, if , no custom view model is used
- public virtual ICustomNodeViewModel? GetCustomViewModel(NodeScript nodeScript)
- {
- return null;
- }
-
///
/// Serializes the object into a string
///
@@ -402,102 +390,4 @@ public abstract class Node : BreakableModel, INode
}
#endregion
-}
-
-///
-/// Represents a kind of node inside a containing storage value of type
-/// .
-///
-/// The type of value the node stores
-public abstract class Node : Node
-{
- private TStorage? _storage;
-
- ///
- protected Node()
- {
- }
-
- ///
- protected Node(string name, string description) : base(name, description)
- {
- }
-
- ///
- /// Gets or sets the storage object of this node, this is saved across sessions
- ///
- public TStorage? Storage
- {
- get => _storage;
- set
- {
- if (SetAndNotify(ref _storage, value))
- StorageModified?.Invoke(this, EventArgs.Empty);
- }
- }
-
- ///
- /// Occurs whenever the storage of this node was modified.
- ///
- public event EventHandler? StorageModified;
-
- ///
- public override string SerializeStorage()
- {
- return CoreJson.SerializeObject(Storage, true);
- }
-
- ///
- public override void DeserializeStorage(string serialized)
- {
- Storage = CoreJson.DeserializeObject(serialized) ?? default(TStorage);
- }
-}
-
-///
-/// Represents a kind of node inside a containing storage value of type
-/// and a view model of type .
-///
-/// The type of value the node stores
-/// The type of view model the node uses
-public abstract class Node : Node where TViewModel : ICustomNodeViewModel
-{
- ///
- protected Node()
- {
- }
-
- ///
- protected Node(string name, string description) : base(name, description)
- {
- }
-
- [Inject]
- internal IKernel Kernel { get; set; } = null!;
-
- ///
- /// Called when a view model is required
- ///
- ///
- public virtual TViewModel GetViewModel(NodeScript nodeScript)
- {
- // Limit to one constructor, there's no need to have more and it complicates things anyway
- ConstructorInfo[] constructors = typeof(TViewModel).GetConstructors();
- if (constructors.Length != 1)
- throw new ArtemisCoreException("Node VMs must have exactly one constructor");
-
- // Find the ScriptConfiguration parameter, it is required by the base constructor so its there for sure
- ParameterInfo? configurationParameter = constructors.First().GetParameters().FirstOrDefault(p => GetType().IsAssignableFrom(p.ParameterType));
-
- if (configurationParameter?.Name == null)
- throw new ArtemisCoreException($"Couldn't find a valid constructor argument on {typeof(TViewModel).Name} with type {GetType().Name}");
- return Kernel.Get(new ConstructorArgument(configurationParameter.Name, this), new ConstructorArgument("script", nodeScript));
- }
-
- ///
- ///
- public override ICustomNodeViewModel? GetCustomViewModel(NodeScript nodeScript)
- {
- return GetViewModel(nodeScript);
- }
}
\ No newline at end of file
diff --git a/src/Artemis.Core/VisualScripting/Nodes/NodeTStorage.cs b/src/Artemis.Core/VisualScripting/Nodes/NodeTStorage.cs
new file mode 100644
index 000000000..81d9e7eac
--- /dev/null
+++ b/src/Artemis.Core/VisualScripting/Nodes/NodeTStorage.cs
@@ -0,0 +1,52 @@
+using System;
+using Artemis.Core;
+
+///
+/// Represents a kind of node inside a containing storage value of type
+/// .
+///
+/// The type of value the node stores
+public abstract class Node : Node
+{
+ private TStorage? _storage;
+
+ ///
+ protected Node()
+ {
+ }
+
+ ///
+ protected Node(string name, string description) : base(name, description)
+ {
+ }
+
+ ///
+ /// Gets or sets the storage object of this node, this is saved across sessions
+ ///
+ public TStorage? Storage
+ {
+ get => _storage;
+ set
+ {
+ if (SetAndNotify(ref _storage, value))
+ StorageModified?.Invoke(this, EventArgs.Empty);
+ }
+ }
+
+ ///
+ /// Occurs whenever the storage of this node was modified.
+ ///
+ public event EventHandler? StorageModified;
+
+ ///
+ public override string SerializeStorage()
+ {
+ return CoreJson.SerializeObject(Storage, true);
+ }
+
+ ///
+ public override void DeserializeStorage(string serialized)
+ {
+ Storage = CoreJson.DeserializeObject(serialized) ?? default(TStorage);
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/VisualScripting/Nodes/NodeTStorageTViewModel.cs b/src/Artemis.Core/VisualScripting/Nodes/NodeTStorageTViewModel.cs
new file mode 100644
index 000000000..1b4109714
--- /dev/null
+++ b/src/Artemis.Core/VisualScripting/Nodes/NodeTStorageTViewModel.cs
@@ -0,0 +1,58 @@
+using System.Linq;
+using System.Reflection;
+using Artemis.Core;
+using Ninject;
+using Ninject.Parameters;
+
+///
+/// Represents a kind of node inside a containing storage value of type
+/// and a view model of type .
+///
+/// The type of value the node stores
+/// The type of view model the node uses
+public abstract class Node : Node, ICustomViewModelNode where TViewModel : ICustomNodeViewModel
+{
+ ///
+ protected Node()
+ {
+ }
+
+ ///
+ protected Node(string name, string description) : base(name, description)
+ {
+ }
+
+ [Inject]
+ internal IKernel Kernel { get; set; } = null!;
+
+ ///
+ /// Called when a view model is required
+ ///
+ ///
+ public virtual TViewModel GetViewModel(NodeScript nodeScript)
+ {
+ // Limit to one constructor, there's no need to have more and it complicates things anyway
+ ConstructorInfo[] constructors = typeof(TViewModel).GetConstructors();
+ if (constructors.Length != 1)
+ throw new ArtemisCoreException("Node VMs must have exactly one constructor");
+
+ // Find the ScriptConfiguration parameter, it is required by the base constructor so its there for sure
+ ParameterInfo? configurationParameter = constructors.First().GetParameters().FirstOrDefault(p => GetType().IsAssignableFrom(p.ParameterType));
+
+ if (configurationParameter?.Name == null)
+ throw new ArtemisCoreException($"Couldn't find a valid constructor argument on {typeof(TViewModel).Name} with type {GetType().Name}");
+ return Kernel.Get(new ConstructorArgument(configurationParameter.Name, this), new ConstructorArgument("script", nodeScript));
+ }
+
+ ///
+ /// Gets or sets the position of the node's custom view model.
+ ///
+ public CustomNodeViewModelPosition ViewModelPosition { get; protected set; } = CustomNodeViewModelPosition.BetweenPinsTop;
+
+ ///
+ ///
+ public ICustomNodeViewModel GetCustomViewModel(NodeScript nodeScript)
+ {
+ return GetViewModel(nodeScript);
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/VisualScripting/InputPin.cs b/src/Artemis.Core/VisualScripting/Pins/InputPin.cs
similarity index 100%
rename from src/Artemis.Core/VisualScripting/InputPin.cs
rename to src/Artemis.Core/VisualScripting/Pins/InputPin.cs
diff --git a/src/Artemis.Core/VisualScripting/InputPinCollection.cs b/src/Artemis.Core/VisualScripting/Pins/InputPinCollection.cs
similarity index 100%
rename from src/Artemis.Core/VisualScripting/InputPinCollection.cs
rename to src/Artemis.Core/VisualScripting/Pins/InputPinCollection.cs
diff --git a/src/Artemis.Core/VisualScripting/ObjectOutputPins.cs b/src/Artemis.Core/VisualScripting/Pins/ObjectOutputPins.cs
similarity index 100%
rename from src/Artemis.Core/VisualScripting/ObjectOutputPins.cs
rename to src/Artemis.Core/VisualScripting/Pins/ObjectOutputPins.cs
diff --git a/src/Artemis.Core/VisualScripting/OutputPin.cs b/src/Artemis.Core/VisualScripting/Pins/OutputPin.cs
similarity index 100%
rename from src/Artemis.Core/VisualScripting/OutputPin.cs
rename to src/Artemis.Core/VisualScripting/Pins/OutputPin.cs
diff --git a/src/Artemis.Core/VisualScripting/OutputPinCollection.cs b/src/Artemis.Core/VisualScripting/Pins/OutputPinCollection.cs
similarity index 100%
rename from src/Artemis.Core/VisualScripting/OutputPinCollection.cs
rename to src/Artemis.Core/VisualScripting/Pins/OutputPinCollection.cs
diff --git a/src/Artemis.Core/VisualScripting/Pin.cs b/src/Artemis.Core/VisualScripting/Pins/Pin.cs
similarity index 100%
rename from src/Artemis.Core/VisualScripting/Pin.cs
rename to src/Artemis.Core/VisualScripting/Pins/Pin.cs
diff --git a/src/Artemis.Core/VisualScripting/PinCollection.cs b/src/Artemis.Core/VisualScripting/Pins/PinCollection.cs
similarity index 100%
rename from src/Artemis.Core/VisualScripting/PinCollection.cs
rename to src/Artemis.Core/VisualScripting/Pins/PinCollection.cs
diff --git a/src/Artemis.Core/VisualScripting/PinDirection.cs b/src/Artemis.Core/VisualScripting/Pins/PinDirection.cs
similarity index 100%
rename from src/Artemis.Core/VisualScripting/PinDirection.cs
rename to src/Artemis.Core/VisualScripting/Pins/PinDirection.cs
diff --git a/src/Artemis.Storage/Migrations/M0021GradientNodes.cs b/src/Artemis.Storage/Migrations/M0021GradientNodes.cs
new file mode 100644
index 000000000..11f062bd7
--- /dev/null
+++ b/src/Artemis.Storage/Migrations/M0021GradientNodes.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Linq;
+using Artemis.Storage.Entities.Profile;
+using Artemis.Storage.Entities.Profile.Nodes;
+using Artemis.Storage.Migrations.Interfaces;
+using LiteDB;
+
+namespace Artemis.Storage.Migrations;
+
+public class M0021GradientNodes : IStorageMigration
+{
+ private void MigrateDataBinding(PropertyEntity property)
+ {
+ NodeScriptEntity script = property.DataBinding.NodeScript;
+ NodeEntity exitNode = script.Nodes.FirstOrDefault(s => s.IsExitNode);
+ if (exitNode == null)
+ return;
+
+ // Create a new node at the same position of the exit node
+ NodeEntity gradientNode = new()
+ {
+ Id = Guid.NewGuid(),
+ Type = "ColorGradientNode",
+ PluginId = Guid.Parse("ffffffff-ffff-ffff-ffff-ffffffffffff"),
+ Name = "Color Gradient",
+ Description = "Outputs a color gradient with the given colors",
+ X = exitNode.X,
+ Y = exitNode.Y,
+ Storage = property.Value // Copy the value of the property into the node storage
+ };
+ script.Nodes.Add(gradientNode);
+
+ // Move all connections of the exit node to the new node
+ foreach (NodeConnectionEntity connection in script.Connections)
+ {
+ if (connection.SourceNode == exitNode.Id)
+ {
+ connection.SourceNode = gradientNode.Id;
+ connection.SourcePinId++;
+ }
+ }
+
+ // Connect the data binding node to the source node
+ script.Connections.Add(new NodeConnectionEntity
+ {
+ SourceType = "ColorGradient",
+ SourceNode = exitNode.Id,
+ SourcePinCollectionId = -1,
+ SourcePinId = 0,
+ TargetType = "ColorGradient",
+ TargetNode = gradientNode.Id,
+ TargetPinCollectionId = -1,
+ TargetPinId = 0,
+ });
+
+ // Move the exit node to the right
+ exitNode.X += 300;
+ exitNode.Y += 30;
+ }
+
+ public int UserVersion => 21;
+
+ public void Apply(LiteRepository repository)
+ {
+ // Find all color gradient data bindings, there's no really good way to do this so infer it from the value
+ ILiteCollection collection = repository.Database.GetCollection();
+ foreach (ProfileEntity profileEntity in collection.FindAll())
+ {
+ foreach (LayerEntity layer in profileEntity.Layers)
+ MigrateDataBinding(layer.LayerBrush.PropertyGroup);
+
+ collection.Update(profileEntity);
+ }
+ }
+
+ private void MigrateDataBinding(PropertyGroupEntity propertyGroup)
+ {
+ foreach (PropertyGroupEntity propertyGroupPropertyGroup in propertyGroup.PropertyGroups)
+ MigrateDataBinding(propertyGroupPropertyGroup);
+
+ foreach (PropertyEntity property in propertyGroup.Properties)
+ {
+ if (property.Value.StartsWith("[{\"Color\":\"") && property.DataBinding?.NodeScript != null && property.DataBinding.IsEnabled)
+ MigrateDataBinding(property);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI.Shared/Controls/GradientPicker/GradientPicker.cs b/src/Artemis.UI.Shared/Controls/GradientPicker/GradientPicker.cs
index e98be34a9..0066ad760 100644
--- a/src/Artemis.UI.Shared/Controls/GradientPicker/GradientPicker.cs
+++ b/src/Artemis.UI.Shared/Controls/GradientPicker/GradientPicker.cs
@@ -59,22 +59,29 @@ public class GradientPicker : TemplatedControl
public static readonly DirectProperty DeleteStopProperty =
AvaloniaProperty.RegisterDirect(nameof(DeleteStop), g => g.DeleteStop);
+ ///
+ /// Gets the color gradient currently being edited, for internal use only
+ ///
+ public static readonly DirectProperty EditingColorGradientProperty =
+ AvaloniaProperty.RegisterDirect(nameof(EditingColorGradient), g => g.EditingColorGradient);
+
private readonly ICommand _deleteStop;
private ColorPicker? _colorPicker;
private Button? _flipStops;
private Border? _gradient;
- private ColorGradient? _lastColorGradient;
private Button? _randomize;
private Button? _rotateStops;
private bool _shiftDown;
private Button? _spreadStops;
private Button? _toggleSeamless;
+ private ColorGradient _colorGradient = null!;
///
/// Creates a new instance of the class.
///
public GradientPicker()
{
+ EditingColorGradient = ColorGradient.GetUnicornBarf();
_deleteStop = ReactiveCommand.Create(s =>
{
if (ColorGradient.Count <= 2)
@@ -143,6 +150,15 @@ public class GradientPicker : TemplatedControl
get => _deleteStop;
private init => SetAndRaise(DeleteStopProperty, ref _deleteStop, value);
}
+
+ ///
+ /// Gets the color gradient backing the editor, this is a copy of .
+ ///
+ public ColorGradient EditingColorGradient
+ {
+ get => _colorGradient;
+ private set => SetAndRaise(EditingColorGradientProperty, ref _colorGradient, value);
+ }
///
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
@@ -167,7 +183,7 @@ public class GradientPicker : TemplatedControl
_flipStops = e.NameScope.Find