diff --git a/src/Artemis.UI.Shared/Controls/DataModelPicker.xaml b/src/Artemis.UI.Shared/Controls/DataModelPicker.xaml index 725091f24..4bea24d97 100644 --- a/src/Artemis.UI.Shared/Controls/DataModelPicker.xaml +++ b/src/Artemis.UI.Shared/Controls/DataModelPicker.xaml @@ -19,7 +19,7 @@ - + diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs index 47f3341d2..17432d696 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs @@ -247,7 +247,7 @@ namespace Artemis.UI.Shared object? value = Parent == null || Parent.IsRootViewModel ? DataModel : DataModelPath?.GetValue(); if (value is DataModel dataModel) { - foreach (var (key, dynamicChild) in dataModel.DynamicChildren) + foreach (string key in dataModel.DynamicChildren.Keys.ToList()) { string childPath = AppendToPath(key); if (Children.Any(c => c.Path != null && c.Path.Equals(childPath))) diff --git a/src/Artemis.UI/Services/RegistrationService.cs b/src/Artemis.UI/Services/RegistrationService.cs index 820ff6fd5..2d90b2a02 100644 --- a/src/Artemis.UI/Services/RegistrationService.cs +++ b/src/Artemis.UI/Services/RegistrationService.cs @@ -126,8 +126,8 @@ namespace Artemis.UI.Services _nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(int), new SKColor(0xFF32CD32)); _nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(double), new SKColor(0xFF1E90FF)); _nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(float), new SKColor(0xFFFF7C00)); - _nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(SKColor), new SKColor(0xFF7630C7)); - _nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(IList), new SKColor(0xFFC842FF)); + _nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(SKColor), new SKColor(0xFFAD3EED)); + _nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(IList), new SKColor(0xFFED3E61)); foreach (Type nodeType in typeof(SumIntegersNode).Assembly.GetTypes().Where(t => typeof(INode).IsAssignableFrom(t) && t.IsPublic && !t.IsAbstract && !t.IsInterface)) _nodeService.RegisterNodeType(Constants.CorePlugin, nodeType); diff --git a/src/Artemis.VisualScripting/Nodes/CustomViewModels/DataModelNodeCustomViewModel.cs b/src/Artemis.VisualScripting/Nodes/CustomViewModels/DataModelNodeCustomViewModel.cs index dccccb92a..4120f4fcf 100644 --- a/src/Artemis.VisualScripting/Nodes/CustomViewModels/DataModelNodeCustomViewModel.cs +++ b/src/Artemis.VisualScripting/Nodes/CustomViewModels/DataModelNodeCustomViewModel.cs @@ -1,6 +1,7 @@ using System.ComponentModel; using Artemis.Core; using Artemis.Core.Modules; +using Artemis.Core.Services; using Stylet; namespace Artemis.VisualScripting.Nodes.CustomViewModels @@ -10,11 +11,17 @@ namespace Artemis.VisualScripting.Nodes.CustomViewModels private readonly DataModelNode _node; private BindableCollection _modules; - public DataModelNodeCustomViewModel(DataModelNode node) : base(node) + public DataModelNodeCustomViewModel(DataModelNode node, ISettingsService settingsService) : base(node) { _node = node; + + ShowFullPaths = settingsService.GetSetting("ProfileEditor.ShowFullPaths", true); + ShowDataModelValues = settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false); } + public PluginSetting ShowFullPaths { get; } + public PluginSetting ShowDataModelValues { get; } + public BindableCollection Modules { get => _modules; @@ -41,7 +48,7 @@ namespace Artemis.VisualScripting.Nodes.CustomViewModels _node.UpdateOutputPin(); } } - + public override void OnActivate() { if (Modules != null) diff --git a/src/Artemis.VisualScripting/Nodes/CustomViews/DataModelNodeCustomView.xaml b/src/Artemis.VisualScripting/Nodes/CustomViews/DataModelNodeCustomView.xaml index e1a1c9d39..c5ff39d78 100644 --- a/src/Artemis.VisualScripting/Nodes/CustomViews/DataModelNodeCustomView.xaml +++ b/src/Artemis.VisualScripting/Nodes/CustomViews/DataModelNodeCustomView.xaml @@ -8,5 +8,9 @@ xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> - + diff --git a/src/Artemis.VisualScripting/Nodes/Easing/CustomViewModels/EasingTypeNodeCustomViewModel.cs b/src/Artemis.VisualScripting/Nodes/Easing/CustomViewModels/EasingTypeNodeCustomViewModel.cs new file mode 100644 index 000000000..6675c211a --- /dev/null +++ b/src/Artemis.VisualScripting/Nodes/Easing/CustomViewModels/EasingTypeNodeCustomViewModel.cs @@ -0,0 +1,55 @@ +using System; +using System.ComponentModel; +using System.Linq; +using Artemis.Core; +using Artemis.VisualScripting.Nodes.CustomViewModels; +using Stylet; + +namespace Artemis.VisualScripting.Nodes.Easing.CustomViewModels +{ + public class EasingTypeNodeCustomViewModel : CustomNodeViewModel + { + private readonly EasingTypeNode _node; + private NodeEasingViewModel _selectedEasingViewModel; + + public EasingTypeNodeCustomViewModel(EasingTypeNode node) : base(node) + { + _node = node; + EasingViewModels = new BindableCollection(Enum.GetValues(typeof(Easings.Functions)) + .Cast() + .Select(e => new NodeEasingViewModel(e))); + } + + public BindableCollection EasingViewModels { get; } + + public NodeEasingViewModel SelectedEasingViewModel + { + get => _selectedEasingViewModel; + set + { + _selectedEasingViewModel = value; + _node.Storage = _selectedEasingViewModel.EasingFunction; + } + } + + public override void OnActivate() + { + _node.PropertyChanged += NodeOnPropertyChanged; + SelectedEasingViewModel = EasingViewModels.FirstOrDefault(vm => vm.EasingFunction == _node.EasingFunction); + } + + public override void OnDeactivate() + { + _node.PropertyChanged -= NodeOnPropertyChanged; + } + + private void NodeOnPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(Node.Storage)) + { + _selectedEasingViewModel = EasingViewModels.FirstOrDefault(vm => vm.EasingFunction == _node.EasingFunction); + NotifyOfPropertyChange(nameof(SelectedEasingViewModel)); + } + } + } +} \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/Easing/CustomViewModels/NodeEasingViewModel.cs b/src/Artemis.VisualScripting/Nodes/Easing/CustomViewModels/NodeEasingViewModel.cs new file mode 100644 index 000000000..66c15fd6c --- /dev/null +++ b/src/Artemis.VisualScripting/Nodes/Easing/CustomViewModels/NodeEasingViewModel.cs @@ -0,0 +1,29 @@ +using System.Windows; +using System.Windows.Media; +using Artemis.Core; +using Humanizer; +using Stylet; + +namespace Artemis.VisualScripting.Nodes.Easing.CustomViewModels +{ + public class NodeEasingViewModel : PropertyChangedBase + { + public NodeEasingViewModel(Easings.Functions easingFunction) + { + EasingFunction = easingFunction; + Description = easingFunction.Humanize(); + + EasingPoints = new PointCollection(); + for (int i = 1; i <= 10; i++) + { + int x = i; + double y = Easings.Interpolate(i / 10.0, EasingFunction) * 10; + EasingPoints.Add(new Point(x, y)); + } + } + + public Easings.Functions EasingFunction { get; } + public PointCollection EasingPoints { get; } + public string Description { get; } + } +} \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/Easing/CustomViews/EasingTypeNodeCustomView.xaml b/src/Artemis.VisualScripting/Nodes/Easing/CustomViews/EasingTypeNodeCustomView.xaml new file mode 100644 index 000000000..8aa3062fe --- /dev/null +++ b/src/Artemis.VisualScripting/Nodes/Easing/CustomViews/EasingTypeNodeCustomView.xaml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/Artemis.VisualScripting/Nodes/Easing/DoubleEasingNode.cs b/src/Artemis.VisualScripting/Nodes/Easing/DoubleEasingNode.cs new file mode 100644 index 000000000..1eb3f744d --- /dev/null +++ b/src/Artemis.VisualScripting/Nodes/Easing/DoubleEasingNode.cs @@ -0,0 +1,68 @@ +using System; +using Artemis.Core; + +namespace Artemis.VisualScripting.Nodes.Easing +{ + [Node("Double Easing", "Outputs an eased double value")] + public class DoubleEasingNode : Node + { + private DateTime _lastEvaluate = DateTime.MinValue; + private float _progress; + private double _currentValue; + private double _sourceValue; + private double _targetValue; + + public DoubleEasingNode() : base("Double Easing", "Outputs an eased double value") + { + Input = CreateInputPin(); + EasingTime = CreateInputPin("delay"); + EasingFunction = CreateInputPin("function"); + + Output = CreateOutputPin(); + } + + public InputPin Input { get; set; } + public InputPin EasingTime { get; set; } + public InputPin EasingFunction { get; set; } + + public OutputPin Output { get; set; } + + public override void Evaluate() + { + DateTime now = DateTime.Now; + + // If the value changed reset progress + if (Math.Abs(_targetValue - Input.Value) > 0.001f) + { + _sourceValue = _currentValue; + _targetValue = Input.Value; + _progress = 0f; + } + + // Update until finished + if (_progress < 1f) + { + Update(); + Output.Value = _currentValue; + } + // Stop updating past 1 and use the target value + else + { + Output.Value = _targetValue; + } + + _lastEvaluate = now; + } + + private void Update() + { + TimeSpan delta = DateTime.Now - _lastEvaluate; + + // In case of odd delta's, keep progress between 0f and 1f + _progress = Math.Clamp(_progress + (float)delta.TotalMilliseconds / EasingTime.Value, 0f, 1f); + + double eased = _sourceValue + (_targetValue - _sourceValue) * Easings.Interpolate(_progress, EasingFunction.Value); + _currentValue = eased; + } + } +} \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/Easing/EasingTypeNode.cs b/src/Artemis.VisualScripting/Nodes/Easing/EasingTypeNode.cs new file mode 100644 index 000000000..89c686b46 --- /dev/null +++ b/src/Artemis.VisualScripting/Nodes/Easing/EasingTypeNode.cs @@ -0,0 +1,22 @@ +using Artemis.Core; +using Artemis.VisualScripting.Nodes.Easing.CustomViewModels; + +namespace Artemis.VisualScripting.Nodes.Easing +{ + [Node("Easing Type", "Outputs a selectable easing type.")] + public class EasingTypeNode : Node + { + public EasingTypeNode() : base("Easing Type", "Outputs a selectable easing type.") + { + Output = CreateOutputPin(); + } + + public OutputPin Output { get; } + public Easings.Functions EasingFunction => Storage as Easings.Functions? ?? Easings.Functions.Linear; + + public override void Evaluate() + { + Output.Value = EasingFunction; + } + } +} \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/Easing/FloatEasingNode.cs b/src/Artemis.VisualScripting/Nodes/Easing/FloatEasingNode.cs new file mode 100644 index 000000000..762bdf64d --- /dev/null +++ b/src/Artemis.VisualScripting/Nodes/Easing/FloatEasingNode.cs @@ -0,0 +1,68 @@ +using System; +using Artemis.Core; + +namespace Artemis.VisualScripting.Nodes.Easing +{ + [Node("Float Easing", "Outputs an eased float value")] + public class FloatEasingNode : Node + { + private DateTime _lastEvaluate = DateTime.MinValue; + private float _progress; + private float _currentValue; + private float _sourceValue; + private float _targetValue; + + public FloatEasingNode() : base("Float Easing", "Outputs an eased float value") + { + Input = CreateInputPin(); + EasingTime = CreateInputPin("delay"); + EasingFunction = CreateInputPin("function"); + + Output = CreateOutputPin(); + } + + public InputPin Input { get; set; } + public InputPin EasingTime { get; set; } + public InputPin EasingFunction { get; set; } + + public OutputPin Output { get; set; } + + public override void Evaluate() + { + DateTime now = DateTime.Now; + + // If the value changed reset progress + if (Math.Abs(_targetValue - Input.Value) > 0.001f) + { + _sourceValue = _currentValue; + _targetValue = Input.Value; + _progress = 0f; + } + + // Update until finished + if (_progress < 1f) + { + Update(); + Output.Value = _currentValue; + } + // Stop updating past 1 and use the target value + else + { + Output.Value = _targetValue; + } + + _lastEvaluate = now; + } + + private void Update() + { + TimeSpan delta = DateTime.Now - _lastEvaluate; + + // In case of odd delta's, keep progress between 0f and 1f + _progress = Math.Clamp(_progress + (float) delta.TotalMilliseconds / EasingTime.Value, 0f, 1f); + + double eased = _sourceValue + (_targetValue - _sourceValue) * Easings.Interpolate(_progress, EasingFunction.Value); + _currentValue = (float) eased; + } + } +} \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/Easing/IntEasingNode.cs b/src/Artemis.VisualScripting/Nodes/Easing/IntEasingNode.cs new file mode 100644 index 000000000..dd6dee610 --- /dev/null +++ b/src/Artemis.VisualScripting/Nodes/Easing/IntEasingNode.cs @@ -0,0 +1,68 @@ +using System; +using Artemis.Core; + +namespace Artemis.VisualScripting.Nodes.Easing +{ + [Node("Integer Easing", "Outputs an eased integer value")] + public class IntEasingNode : Node + { + private DateTime _lastEvaluate = DateTime.MinValue; + private float _progress; + private int _currentValue; + private int _sourceValue; + private int _targetValue; + + public IntEasingNode() : base("Integer Easing", "Outputs an eased integer value") + { + Input = CreateInputPin(); + EasingTime = CreateInputPin("delay"); + EasingFunction = CreateInputPin("function"); + + Output = CreateOutputPin(); + } + + public InputPin Input { get; set; } + public InputPin EasingTime { get; set; } + public InputPin EasingFunction { get; set; } + + public OutputPin Output { get; set; } + + public override void Evaluate() + { + DateTime now = DateTime.Now; + + // If the value changed reset progress + if (_targetValue != Input.Value) + { + _sourceValue = _currentValue; + _targetValue = Input.Value; + _progress = 0f; + } + + // Update until finished + if (_progress < 1f) + { + Update(); + Output.Value = _currentValue; + } + // Stop updating past 1 and use the target value + else + { + Output.Value = _targetValue; + } + + _lastEvaluate = now; + } + + private void Update() + { + TimeSpan delta = DateTime.Now - _lastEvaluate; + + // In case of odd delta's, keep progress between 0f and 1f + _progress = Math.Clamp(_progress + (float) delta.TotalMilliseconds / EasingTime.Value, 0f, 1f); + + double eased = _sourceValue + (_targetValue - _sourceValue) * Easings.Interpolate(_progress, EasingFunction.Value); + _currentValue = (int) Math.Round(eased, MidpointRounding.AwayFromZero); + } + } +} \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/Easing/SKColorEasingNode.cs b/src/Artemis.VisualScripting/Nodes/Easing/SKColorEasingNode.cs new file mode 100644 index 000000000..111ebd647 --- /dev/null +++ b/src/Artemis.VisualScripting/Nodes/Easing/SKColorEasingNode.cs @@ -0,0 +1,67 @@ +using System; +using Artemis.Core; +using SkiaSharp; + +namespace Artemis.VisualScripting.Nodes.Easing +{ + [Node("Color Easing", "Outputs an eased color value")] + public class SKColorEasingNode : Node + { + private DateTime _lastEvaluate = DateTime.MinValue; + private float _progress; + private SKColor _currentValue; + private SKColor _sourceValue; + private SKColor _targetValue; + + public SKColorEasingNode() : base("Color Easing", "Outputs an eased color value") + { + Input = CreateInputPin(); + EasingTime = CreateInputPin("delay"); + EasingFunction = CreateInputPin("function"); + + Output = CreateOutputPin(); + } + + public InputPin Input { get; set; } + public InputPin EasingTime { get; set; } + public InputPin EasingFunction { get; set; } + + public OutputPin Output { get; set; } + + public override void Evaluate() + { + DateTime now = DateTime.Now; + + // If the value changed reset progress + if (_targetValue != Input.Value) + { + _sourceValue = _currentValue; + _targetValue = Input.Value; + _progress = 0f; + } + + // Update until finished + if (_progress < 1f) + { + Update(); + Output.Value = _currentValue; + } + // Stop updating past 1 and use the target value + else + { + Output.Value = _targetValue; + } + + _lastEvaluate = now; + } + + private void Update() + { + TimeSpan delta = DateTime.Now - _lastEvaluate; + + // In case of odd delta's, keep progress between 0f and 1f + _progress = Math.Clamp(_progress + (float) delta.TotalMilliseconds / EasingTime.Value, 0f, 1f); + _currentValue = _sourceValue.Interpolate(_targetValue, (float) Easings.Interpolate(_progress, EasingFunction.Value)); + } + } +} \ No newline at end of file