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