From 28534cb57a564e448d6137a3a577afee070b7288 Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 27 Mar 2022 15:29:58 +0200 Subject: [PATCH] Nodes - Added maths node Nodes - Added visual representation of easing types to easings node --- src/Artemis.UI.Linux/packages.lock.json | 1 + src/Artemis.UI.MacOS/packages.lock.json | 1 + .../VisualScripting/CustomNodeViewModel.cs | 10 ++++- src/Artemis.UI.Windows/packages.lock.json | 1 + src/Artemis.UI/packages.lock.json | 1 + .../Artemis.VisualScripting.csproj | 1 + .../DataModelEventNodeCustomViewModel.cs | 4 +- .../DataModelNodeCustomViewModel.cs | 4 +- .../EasingTypeNodeCustomViewModel.cs | 43 +++++------------- .../CustomViewModels/NodeEasingViewModel.cs | 3 +- .../EasingTypeNodeCustomView.axaml | 9 ++-- .../Easing/CustomViews/NodeEasingView.axaml | 19 ++++++++ .../CustomViews/NodeEasingView.axaml.cs | 19 ++++++++ .../MathExpressionNodeCustomViewModel.cs | 27 +++++++++++- .../MathExpressionNodeCustomView.axaml | 14 ++++++ .../MathExpressionNodeCustomView.axaml.cs | 24 ++++++++++ .../MathExpressionNodeCustomView.xaml | 11 ----- .../Nodes/Maths/ExpressionNode.cs | 44 ++++++++++++++++++- .../packages.lock.json | 17 +++---- 19 files changed, 190 insertions(+), 63 deletions(-) create mode 100644 src/Artemis.VisualScripting/Nodes/Easing/CustomViews/NodeEasingView.axaml create mode 100644 src/Artemis.VisualScripting/Nodes/Easing/CustomViews/NodeEasingView.axaml.cs create mode 100644 src/Artemis.VisualScripting/Nodes/Maths/CustomViews/MathExpressionNodeCustomView.axaml create mode 100644 src/Artemis.VisualScripting/Nodes/Maths/CustomViews/MathExpressionNodeCustomView.axaml.cs delete mode 100644 src/Artemis.VisualScripting/Nodes/Maths/CustomViews/MathExpressionNodeCustomView.xaml diff --git a/src/Artemis.UI.Linux/packages.lock.json b/src/Artemis.UI.Linux/packages.lock.json index 66c4330a9..078afba5d 100644 --- a/src/Artemis.UI.Linux/packages.lock.json +++ b/src/Artemis.UI.Linux/packages.lock.json @@ -1820,6 +1820,7 @@ "Ninject": "3.3.4", "NoStringEvaluating": "2.2.2", "ReactiveUI": "17.1.50", + "ReactiveUI.Validation": "2.2.1", "SkiaSharp": "2.88.0-preview.178" } } diff --git a/src/Artemis.UI.MacOS/packages.lock.json b/src/Artemis.UI.MacOS/packages.lock.json index 66c4330a9..078afba5d 100644 --- a/src/Artemis.UI.MacOS/packages.lock.json +++ b/src/Artemis.UI.MacOS/packages.lock.json @@ -1820,6 +1820,7 @@ "Ninject": "3.3.4", "NoStringEvaluating": "2.2.2", "ReactiveUI": "17.1.50", + "ReactiveUI.Validation": "2.2.1", "SkiaSharp": "2.88.0-preview.178" } } diff --git a/src/Artemis.UI.Shared/VisualScripting/CustomNodeViewModel.cs b/src/Artemis.UI.Shared/VisualScripting/CustomNodeViewModel.cs index 211ab8517..fc165e7e1 100644 --- a/src/Artemis.UI.Shared/VisualScripting/CustomNodeViewModel.cs +++ b/src/Artemis.UI.Shared/VisualScripting/CustomNodeViewModel.cs @@ -3,13 +3,14 @@ using System.ComponentModel; using System.Reactive.Disposables; using Artemis.Core; using ReactiveUI; +using ReactiveUI.Validation.Helpers; namespace Artemis.UI.Shared.VisualScripting; /// /// Represents a custom view model for a node /// -public abstract class CustomNodeViewModel : ActivatableViewModelBase, ICustomNodeViewModel +public abstract class CustomNodeViewModel : ReactiveValidationObject, IActivatableViewModel, ICustomNodeViewModel { /// /// Creates a new instance of the class. @@ -38,6 +39,13 @@ public abstract class CustomNodeViewModel : ActivatableViewModelBase, ICustomNod /// public INodeScript Script { get; } + #region Implementation of IActivatableViewModel + + /// + public ViewModelActivator Activator { get; } = new(); + + #endregion + /// /// Invokes the event /// diff --git a/src/Artemis.UI.Windows/packages.lock.json b/src/Artemis.UI.Windows/packages.lock.json index f78508371..51d6f98cb 100644 --- a/src/Artemis.UI.Windows/packages.lock.json +++ b/src/Artemis.UI.Windows/packages.lock.json @@ -1836,6 +1836,7 @@ "Ninject": "3.3.4", "NoStringEvaluating": "2.2.2", "ReactiveUI": "17.1.50", + "ReactiveUI.Validation": "2.2.1", "SkiaSharp": "2.88.0-preview.178" } } diff --git a/src/Artemis.UI/packages.lock.json b/src/Artemis.UI/packages.lock.json index a3900f74e..f67a1ef34 100644 --- a/src/Artemis.UI/packages.lock.json +++ b/src/Artemis.UI/packages.lock.json @@ -1807,6 +1807,7 @@ "Ninject": "3.3.4", "NoStringEvaluating": "2.2.2", "ReactiveUI": "17.1.50", + "ReactiveUI.Validation": "2.2.1", "SkiaSharp": "2.88.0-preview.178" } } diff --git a/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj b/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj index ae61ee5c3..3fbc19ba2 100644 --- a/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj +++ b/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj @@ -14,6 +14,7 @@ + diff --git a/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelEventNodeCustomViewModel.cs b/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelEventNodeCustomViewModel.cs index 167e9c2b9..2da876724 100644 --- a/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelEventNodeCustomViewModel.cs +++ b/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelEventNodeCustomViewModel.cs @@ -55,13 +55,13 @@ public class DataModelEventNodeCustomViewModel : CustomNodeViewModel public ObservableCollection? Modules { get => _modules; - set => RaiseAndSetIfChanged(ref _modules, value); + set => this.RaiseAndSetIfChanged(ref _modules, value); } public DataModelPath? DataModelPath { get => _dataModelPath; - set => RaiseAndSetIfChanged(ref _dataModelPath, value); + set => this.RaiseAndSetIfChanged(ref _dataModelPath, value); } private void UpdateDataModelPath(DataModelPathEntity? entity) diff --git a/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelNodeCustomViewModel.cs b/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelNodeCustomViewModel.cs index a0300bd7f..c97046eb6 100644 --- a/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelNodeCustomViewModel.cs +++ b/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelNodeCustomViewModel.cs @@ -54,13 +54,13 @@ public class DataModelNodeCustomViewModel : CustomNodeViewModel public ObservableCollection? Modules { get => _modules; - set => RaiseAndSetIfChanged(ref _modules, value); + set => this.RaiseAndSetIfChanged(ref _modules, value); } public DataModelPath? DataModelPath { get => _dataModelPath; - set => RaiseAndSetIfChanged(ref _dataModelPath, value); + set => this.RaiseAndSetIfChanged(ref _dataModelPath, value); } private void UpdateDataModelPath(DataModelPathEntity? entity) diff --git a/src/Artemis.VisualScripting/Nodes/Easing/CustomViewModels/EasingTypeNodeCustomViewModel.cs b/src/Artemis.VisualScripting/Nodes/Easing/CustomViewModels/EasingTypeNodeCustomViewModel.cs index 996063499..d79da8534 100644 --- a/src/Artemis.VisualScripting/Nodes/Easing/CustomViewModels/EasingTypeNodeCustomViewModel.cs +++ b/src/Artemis.VisualScripting/Nodes/Easing/CustomViewModels/EasingTypeNodeCustomViewModel.cs @@ -1,54 +1,35 @@ using System.Collections.ObjectModel; using Artemis.Core; +using Artemis.UI.Shared.Services.NodeEditor; +using Artemis.UI.Shared.Services.NodeEditor.Commands; using Artemis.UI.Shared.VisualScripting; +using ReactiveUI; namespace Artemis.VisualScripting.Nodes.Easing.CustomViewModels; public class EasingTypeNodeCustomViewModel : CustomNodeViewModel { private readonly EasingTypeNode _node; - private NodeEasingViewModel _selectedEasingViewModel; + private readonly INodeEditorService _nodeEditorService; - public EasingTypeNodeCustomViewModel(EasingTypeNode node, INodeScript script) : base(node, script) + public EasingTypeNodeCustomViewModel(EasingTypeNode node, INodeScript script, INodeEditorService nodeEditorService) : base(node, script) { _node = node; + _nodeEditorService = nodeEditorService; + + NodeModified += (_, _) => this.RaisePropertyChanged(nameof(SelectedEasingViewModel)); EasingViewModels = new ObservableCollection(Enum.GetValues(typeof(Easings.Functions)).Cast().Select(e => new NodeEasingViewModel(e))); } public ObservableCollection EasingViewModels { get; } - public NodeEasingViewModel SelectedEasingViewModel + public NodeEasingViewModel? SelectedEasingViewModel { - get => _selectedEasingViewModel; + get => EasingViewModels.FirstOrDefault(e => e.EasingFunction == _node.Storage); set { - _selectedEasingViewModel = value; - _node.Storage = _selectedEasingViewModel.EasingFunction; + if (value != null && _node.Storage != value.EasingFunction) + _nodeEditorService.ExecuteCommand(Script, new UpdateStorage(_node, value.EasingFunction)); } } - - // public override void OnActivate() - // { - // _node.PropertyChanged += NodeOnPropertyChanged; - // SelectedEasingViewModel = GetNodeEasingViewModel(); - // } - // - // public override void OnDeactivate() - // { - // _node.PropertyChanged -= NodeOnPropertyChanged; - // } - // - // private void NodeOnPropertyChanged(object sender, PropertyChangedEventArgs e) - // { - // if (e.PropertyName == nameof(_node.Storage)) - // { - // _selectedEasingViewModel = GetNodeEasingViewModel(); - // NotifyOfPropertyChange(nameof(SelectedEasingViewModel)); - // } - // } - - private NodeEasingViewModel GetNodeEasingViewModel() - { - return EasingViewModels.FirstOrDefault(vm => vm.EasingFunction == _node.Storage); - } } \ 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 index 9fb73fd42..21cd33dc0 100644 --- a/src/Artemis.VisualScripting/Nodes/Easing/CustomViewModels/NodeEasingViewModel.cs +++ b/src/Artemis.VisualScripting/Nodes/Easing/CustomViewModels/NodeEasingViewModel.cs @@ -15,9 +15,8 @@ public class NodeEasingViewModel : ViewModelBase EasingPoints = new List(); 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)); + EasingPoints.Add(new Point(i, y)); } } diff --git a/src/Artemis.VisualScripting/Nodes/Easing/CustomViews/EasingTypeNodeCustomView.axaml b/src/Artemis.VisualScripting/Nodes/Easing/CustomViews/EasingTypeNodeCustomView.axaml index c4154fe81..9a002cd6e 100644 --- a/src/Artemis.VisualScripting/Nodes/Easing/CustomViews/EasingTypeNodeCustomView.axaml +++ b/src/Artemis.VisualScripting/Nodes/Easing/CustomViews/EasingTypeNodeCustomView.axaml @@ -2,8 +2,9 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared" + xmlns:customViewModels="clr-namespace:Artemis.VisualScripting.Nodes.Easing.CustomViewModels" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - x:Class="Artemis.VisualScripting.Nodes.Easing.CustomViews.EasingTypeNodeCustomView"> - - + x:Class="Artemis.VisualScripting.Nodes.Easing.CustomViews.EasingTypeNodeCustomView" + x:DataType="customViewModels:EasingTypeNodeCustomViewModel"> + + \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/Easing/CustomViews/NodeEasingView.axaml b/src/Artemis.VisualScripting/Nodes/Easing/CustomViews/NodeEasingView.axaml new file mode 100644 index 000000000..3e2bc8287 --- /dev/null +++ b/src/Artemis.VisualScripting/Nodes/Easing/CustomViews/NodeEasingView.axaml @@ -0,0 +1,19 @@ + + + + + + diff --git a/src/Artemis.VisualScripting/Nodes/Easing/CustomViews/NodeEasingView.axaml.cs b/src/Artemis.VisualScripting/Nodes/Easing/CustomViews/NodeEasingView.axaml.cs new file mode 100644 index 000000000..dbb4a1392 --- /dev/null +++ b/src/Artemis.VisualScripting/Nodes/Easing/CustomViews/NodeEasingView.axaml.cs @@ -0,0 +1,19 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Artemis.VisualScripting.Nodes.Easing.CustomViews +{ + public partial class NodeEasingView : UserControl + { + public NodeEasingView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/src/Artemis.VisualScripting/Nodes/Maths/CustomViewModels/MathExpressionNodeCustomViewModel.cs b/src/Artemis.VisualScripting/Nodes/Maths/CustomViewModels/MathExpressionNodeCustomViewModel.cs index ab443be24..6453f5f34 100644 --- a/src/Artemis.VisualScripting/Nodes/Maths/CustomViewModels/MathExpressionNodeCustomViewModel.cs +++ b/src/Artemis.VisualScripting/Nodes/Maths/CustomViewModels/MathExpressionNodeCustomViewModel.cs @@ -1,11 +1,36 @@ using Artemis.Core; +using Artemis.UI.Shared.Services.NodeEditor; +using Artemis.UI.Shared.Services.NodeEditor.Commands; using Artemis.UI.Shared.VisualScripting; +using ReactiveUI; +using ReactiveUI.Validation.Extensions; namespace Artemis.VisualScripting.Nodes.Maths.CustomViewModels; public class MathExpressionNodeCustomViewModel : CustomNodeViewModel { - public MathExpressionNodeCustomViewModel(INode node, INodeScript script) : base(node, script) + private readonly MathExpressionNode _node; + private readonly INodeEditorService _nodeEditorService; + private string? _inputValue; + + public MathExpressionNodeCustomViewModel(MathExpressionNode node, INodeScript script, INodeEditorService nodeEditorService) : base(node, script) { + _node = node; + _nodeEditorService = nodeEditorService; + + NodeModified += (_, _) => InputValue = _node.Storage; + this.ValidationRule(vm => vm.InputValue, value => _node.IsSyntaxValid(value), value => _node.GetSyntaxErrors(value)); + } + + public string? InputValue + { + get => _inputValue; + set => this.RaiseAndSetIfChanged(ref _inputValue, value); + } + + public void UpdateInputValue() + { + if (!HasErrors && _node.Storage != InputValue) + _nodeEditorService.ExecuteCommand(Script, new UpdateStorage(_node, InputValue)); } } \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/Maths/CustomViews/MathExpressionNodeCustomView.axaml b/src/Artemis.VisualScripting/Nodes/Maths/CustomViews/MathExpressionNodeCustomView.axaml new file mode 100644 index 000000000..860cb78fd --- /dev/null +++ b/src/Artemis.VisualScripting/Nodes/Maths/CustomViews/MathExpressionNodeCustomView.axaml @@ -0,0 +1,14 @@ + + + \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/Maths/CustomViews/MathExpressionNodeCustomView.axaml.cs b/src/Artemis.VisualScripting/Nodes/Maths/CustomViews/MathExpressionNodeCustomView.axaml.cs new file mode 100644 index 000000000..810b621e2 --- /dev/null +++ b/src/Artemis.VisualScripting/Nodes/Maths/CustomViews/MathExpressionNodeCustomView.axaml.cs @@ -0,0 +1,24 @@ +using Artemis.VisualScripting.Nodes.Maths.CustomViewModels; +using Avalonia.Interactivity; +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; + +namespace Artemis.VisualScripting.Nodes.Maths.CustomViews; + +public class MathExpressionNodeCustomView : ReactiveUserControl +{ + public MathExpressionNodeCustomView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + + private void InputElement_OnLostFocus(object? sender, RoutedEventArgs e) + { + ViewModel?.UpdateInputValue(); + } +} \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/Maths/CustomViews/MathExpressionNodeCustomView.xaml b/src/Artemis.VisualScripting/Nodes/Maths/CustomViews/MathExpressionNodeCustomView.xaml deleted file mode 100644 index e39eb33ca..000000000 --- a/src/Artemis.VisualScripting/Nodes/Maths/CustomViews/MathExpressionNodeCustomView.xaml +++ /dev/null @@ -1,11 +0,0 @@ - - - \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/Maths/ExpressionNode.cs b/src/Artemis.VisualScripting/Nodes/Maths/ExpressionNode.cs index 4c41be75c..840760f3d 100644 --- a/src/Artemis.VisualScripting/Nodes/Maths/ExpressionNode.cs +++ b/src/Artemis.VisualScripting/Nodes/Maths/ExpressionNode.cs @@ -2,6 +2,7 @@ using Artemis.VisualScripting.Nodes.Maths.CustomViewModels; using NoStringEvaluating.Contract; using NoStringEvaluating.Contract.Variables; +using NoStringEvaluating.Models.FormulaChecker; using NoStringEvaluating.Models.Values; namespace Artemis.VisualScripting.Nodes.Maths; @@ -10,14 +11,16 @@ namespace Artemis.VisualScripting.Nodes.Maths; public class MathExpressionNode : Node { private readonly INoStringEvaluator _evaluator; + private readonly IFormulaChecker _checker; private readonly PinsVariablesContainer _variables; #region Constructors - public MathExpressionNode(INoStringEvaluator evaluator) + public MathExpressionNode(INoStringEvaluator evaluator, IFormulaChecker checker) : base("Math Expression", "Outputs the result of a math expression.") { _evaluator = evaluator; + _checker = checker; Output = CreateOutputPin(); Values = CreateInputPinCollection("Values", 2); Values.PinAdded += (_, _) => SetPinNames(); @@ -70,6 +73,45 @@ public class MathExpressionNode : Node