diff --git a/src/.idea/.idea.Artemis/.idea/avalonia.xml b/src/.idea/.idea.Artemis/.idea/avalonia.xml
index b11284c50..07f14ce84 100644
--- a/src/.idea/.idea.Artemis/.idea/avalonia.xml
+++ b/src/.idea/.idea.Artemis/.idea/avalonia.xml
@@ -41,6 +41,7 @@
+
@@ -52,6 +53,9 @@
+
+
+
diff --git a/src/Artemis.Core/Models/Profile/Conditions/EventCondition.cs b/src/Artemis.Core/Models/Profile/Conditions/EventCondition.cs
index 26c262cd0..1942aa169 100644
--- a/src/Artemis.Core/Models/Profile/Conditions/EventCondition.cs
+++ b/src/Artemis.Core/Models/Profile/Conditions/EventCondition.cs
@@ -55,7 +55,7 @@ public class EventCondition : CorePropertyChanged, INodeScriptCondition
public NodeScript Script
{
get => _script;
- set => SetAndNotify(ref _script, value);
+ private set => SetAndNotify(ref _script, value);
}
///
diff --git a/src/Artemis.Core/Services/NodeService.cs b/src/Artemis.Core/Services/NodeService.cs
index c0482363a..70c7d2e9b 100644
--- a/src/Artemis.Core/Services/NodeService.cs
+++ b/src/Artemis.Core/Services/NodeService.cs
@@ -3,7 +3,9 @@ using System.Collections.Generic;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
+using Artemis.Core.VisualScripting;
using Artemis.Storage.Entities.Profile.Nodes;
+using Newtonsoft.Json;
using Ninject;
using SkiaSharp;
@@ -80,6 +82,21 @@ namespace Artemis.Core.Services
return NodeTypeStore.AddColor(type, color, plugin);
}
+ public string ExportScript(NodeScript nodeScript)
+ {
+ nodeScript.Save();
+ return JsonConvert.SerializeObject(nodeScript.Entity, IProfileService.ExportSettings);
+ }
+
+ public void ImportScript(string json, NodeScript target)
+ {
+ NodeScriptEntity? entity = JsonConvert.DeserializeObject(json);
+ if (entity == null)
+ throw new ArtemisCoreException("Failed to load node script");
+
+ target.LoadFromEntity(entity);
+ }
+
private INode CreateNode(INodeScript script, NodeEntity? entity, Type nodeType)
{
INode node = _kernel.Get(nodeType) as INode ?? throw new InvalidOperationException($"Node {nodeType} is not an INode");
@@ -135,5 +152,8 @@ namespace Artemis.Core.Services
/// The type to associate the color with
/// The color to display
TypeColorRegistration RegisterTypeColor(Plugin plugin, Type type, SKColor color);
+
+ string ExportScript(NodeScript nodeScript);
+ void ImportScript(string json, NodeScript target);
}
}
\ 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 2ca393ca6..b47ff5a07 100644
--- a/src/Artemis.Core/VisualScripting/Internal/DataBindingExitNode.cs
+++ b/src/Artemis.Core/VisualScripting/Internal/DataBindingExitNode.cs
@@ -16,7 +16,8 @@ namespace Artemis.Core.Internal
DataBinding = dataBinding;
DataBinding.DataBindingPropertiesCleared += DataBindingOnDataBindingPropertiesCleared;
DataBinding.DataBindingPropertyRegistered += DataBindingOnDataBindingPropertyRegistered;
-
+ Id = IExitNode.NodeId;
+
CreateInputPins();
}
diff --git a/src/Artemis.Core/VisualScripting/Node.cs b/src/Artemis.Core/VisualScripting/Node.cs
index 70804e43e..a7f155e17 100644
--- a/src/Artemis.Core/VisualScripting/Node.cs
+++ b/src/Artemis.Core/VisualScripting/Node.cs
@@ -15,14 +15,14 @@ public abstract class Node : CorePropertyChanged, INode
public event EventHandler? Resetting;
#region Properties & Fields
-
+
private Guid _id;
///
public Guid Id
{
get => _id;
- set => SetAndNotify(ref _id , value);
+ set => SetAndNotify(ref _id, value);
}
private string _name;
@@ -73,7 +73,7 @@ public abstract class Node : CorePropertyChanged, INode
public IReadOnlyCollection Pins => new ReadOnlyCollection(_pins);
private readonly List _pinCollections = new();
-
+
///
public IReadOnlyCollection PinCollections => new ReadOnlyCollection(_pinCollections);
@@ -88,6 +88,7 @@ public abstract class Node : CorePropertyChanged, INode
{
_name = string.Empty;
_description = string.Empty;
+ _id = Guid.NewGuid();
}
///
@@ -97,6 +98,7 @@ public abstract class Node : CorePropertyChanged, INode
{
_name = name;
_description = description;
+ _id = Guid.NewGuid();
}
#endregion
diff --git a/src/Artemis.Core/VisualScripting/NodeScript.cs b/src/Artemis.Core/VisualScripting/NodeScript.cs
index 22909973f..dc7b4e0cf 100644
--- a/src/Artemis.Core/VisualScripting/NodeScript.cs
+++ b/src/Artemis.Core/VisualScripting/NodeScript.cs
@@ -29,7 +29,7 @@ namespace Artemis.Core
#region Properties & Fields
- internal NodeScriptEntity Entity { get; }
+ internal NodeScriptEntity Entity { get; private set; }
///
public string Name { get; }
@@ -183,8 +183,15 @@ namespace Artemis.Core
LoadConnections();
}
+ internal void LoadFromEntity(NodeScriptEntity entity)
+ {
+ Entity = entity;
+ Load();
+ }
+
private void LoadExistingNode(INode node, NodeEntity nodeEntity)
{
+ node.Id = nodeEntity.Id;
node.X = nodeEntity.X;
node.Y = nodeEntity.Y;
@@ -245,17 +252,21 @@ namespace Artemis.Core
// Clear existing connections on input pins, we don't want none of that now
if (targetPin.Direction == PinDirection.Input)
+ {
while (targetPin.ConnectedTo.Any())
targetPin.DisconnectFrom(targetPin.ConnectedTo[0]);
+ }
if (sourcePin.Direction == PinDirection.Input)
+ {
while (sourcePin.ConnectedTo.Any())
sourcePin.DisconnectFrom(sourcePin.ConnectedTo[0]);
+ }
// Only connect the nodes if they aren't already connected (LoadConnections may be called twice or more)
- if (!targetPin.ConnectedTo.Contains(sourcePin))
+ if (!targetPin.ConnectedTo.Contains(sourcePin) && targetPin.IsTypeCompatible(sourcePin.Type))
targetPin.ConnectTo(sourcePin);
- if (!sourcePin.ConnectedTo.Contains(targetPin))
+ if (!sourcePin.ConnectedTo.Contains(targetPin) && sourcePin.IsTypeCompatible(targetPin.Type))
sourcePin.ConnectTo(targetPin);
}
}
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/EventConditionViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/EventConditionViewModel.cs
index b8d5a546d..858dadc82 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/EventConditionViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/EventConditionViewModel.cs
@@ -16,6 +16,7 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes;
public class EventConditionViewModel : ActivatableViewModelBase
{
private readonly EventCondition _eventCondition;
+ private readonly INodeService _nodeService;
private readonly IProfileEditorService _profileEditorService;
private readonly ISettingsService _settingsService;
private readonly ObservableAsPropertyHelper _showOverlapOptions;
@@ -26,18 +27,15 @@ public class EventConditionViewModel : ActivatableViewModelBase
private ObservableAsPropertyHelper? _selectedToggleOffMode;
private ObservableAsPropertyHelper? _selectedTriggerMode;
- public EventConditionViewModel(EventCondition eventCondition, IProfileEditorService profileEditorService, IWindowService windowService, ISettingsService settingsService)
+ public EventConditionViewModel(EventCondition eventCondition, IProfileEditorService profileEditorService, INodeService nodeService, IWindowService windowService, ISettingsService settingsService)
{
_eventCondition = eventCondition;
_profileEditorService = profileEditorService;
+ _nodeService = nodeService;
_windowService = windowService;
_settingsService = settingsService;
- _showOverlapOptions = this.WhenAnyValue(vm => vm.SelectedTriggerMode)
- .Select(m => m == 0)
- .ToProperty(this, vm => vm.ShowOverlapOptions);
- _showToggleOffOptions = this.WhenAnyValue(vm => vm.SelectedTriggerMode)
- .Select(m => m == 1)
- .ToProperty(this, vm => vm.ShowToggleOffOptions);
+ _showOverlapOptions = this.WhenAnyValue(vm => vm.SelectedTriggerMode).Select(m => m == 0).ToProperty(this, vm => vm.ShowOverlapOptions);
+ _showToggleOffOptions = this.WhenAnyValue(vm => vm.SelectedTriggerMode).Select(m => m == 1).ToProperty(this, vm => vm.ShowToggleOffOptions);
this.WhenActivated(d =>
{
@@ -82,6 +80,6 @@ public class EventConditionViewModel : ActivatableViewModelBase
private async Task ExecuteOpenEditor()
{
- await _windowService.ShowDialogAsync(("nodeScript", _eventCondition.NodeScript));
+ await _windowService.ShowDialogAsync(("nodeScript", _eventCondition.Script));
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/StaticConditionViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/StaticConditionViewModel.cs
index c6e7dadd7..971ab5b83 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/StaticConditionViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/StaticConditionViewModel.cs
@@ -51,6 +51,6 @@ public class StaticConditionViewModel : ActivatableViewModelBase
private async Task ExecuteOpenEditor()
{
- await _windowService.ShowDialogAsync(("nodeScript", _staticCondition.NodeScript));
+ await _windowService.ShowDialogAsync(("nodeScript", _staticCondition.Script));
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarViewModel.cs
index 31589458d..54cb1e197 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarViewModel.cs
@@ -12,7 +12,6 @@ using Artemis.UI.Screens.Sidebar;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.ProfileEditor;
-using Artemis.UI.Shared.Services.ProfileEditor.Commands;
using Newtonsoft.Json;
using ReactiveUI;
using Serilog;
@@ -27,10 +26,10 @@ public class MenuBarViewModel : ActivatableViewModelBase
private readonly ISettingsService _settingsService;
private readonly IWindowService _windowService;
private ProfileEditorHistory? _history;
- private ObservableAsPropertyHelper? _suspendedEditing;
private ObservableAsPropertyHelper? _isSuspended;
private ObservableAsPropertyHelper? _profileConfiguration;
private ObservableAsPropertyHelper? _profileElement;
+ private ObservableAsPropertyHelper? _suspendedEditing;
public MenuBarViewModel(ILogger logger, IProfileEditorService profileEditorService, IProfileService profileService, ISettingsService settingsService, IWindowService windowService)
{
@@ -62,26 +61,26 @@ public class MenuBarViewModel : ActivatableViewModelBase
DuplicateProfile = ReactiveCommand.Create(ExecuteDuplicateProfile, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null));
ToggleSuspendedEditing = ReactiveCommand.Create(ExecuteToggleSuspendedEditing);
ToggleBooleanSetting = ReactiveCommand.Create>(ExecuteToggleBooleanSetting);
- OpenUri = ReactiveCommand.CreateFromTask(ExecuteOpenUri);
+ OpenUri = ReactiveCommand.Create(s => Process.Start(new ProcessStartInfo(s) {UseShellExecute = true, Verb = "open"}));
}
public ReactiveCommand AddFolder { get; }
public ReactiveCommand AddLayer { get; }
public ReactiveCommand ToggleSuspended { get; }
public ReactiveCommand ViewProperties { get; }
- public ReactiveCommand AdaptProfile { get; }
+ public ReactiveCommand AdaptProfile { get; }
public ReactiveCommand DeleteProfile { get; }
public ReactiveCommand ExportProfile { get; }
public ReactiveCommand DuplicateProfile { get; }
public ReactiveCommand, Unit> ToggleBooleanSetting { get; }
public ReactiveCommand OpenUri { get; }
public ReactiveCommand ToggleSuspendedEditing { get; }
-
+
public ProfileConfiguration? ProfileConfiguration => _profileConfiguration?.Value;
public RenderProfileElement? ProfileElement => _profileElement?.Value;
public bool IsSuspended => _isSuspended?.Value ?? false;
public bool SuspendedEditing => _suspendedEditing?.Value ?? false;
-
+
public PluginSetting AutoSuspend => _settingsService.GetSetting("ProfileEditor.AutoSuspend", true);
public PluginSetting FocusSelectedLayer => _settingsService.GetSetting("ProfileEditor.FocusSelectedLayer", false);
public PluginSetting ShowDataModelValues => _settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false);
@@ -123,6 +122,7 @@ public class MenuBarViewModel : ActivatableViewModelBase
("profileConfiguration", ProfileConfiguration)
);
}
+
private async Task ExecuteAdaptProfile()
{
if (ProfileConfiguration?.Profile == null)
@@ -190,28 +190,15 @@ public class MenuBarViewModel : ActivatableViewModelBase
ProfileConfigurationExportModel export = _profileService.ExportProfile(ProfileConfiguration);
_profileService.ImportProfile(ProfileConfiguration.Category, export, true, false, "copy");
}
-
+
private void ExecuteToggleSuspendedEditing()
{
_profileEditorService.ChangeSuspendedEditing(!SuspendedEditing);
}
-
+
private void ExecuteToggleBooleanSetting(PluginSetting setting)
{
setting.Value = !setting.Value;
setting.Save();
}
-
- private async Task ExecuteOpenUri(string uri)
- {
- try
- {
- Process.Start(new ProcessStartInfo(uri) {UseShellExecute = true, Verb = "open"});
- }
- catch (Exception e)
- {
- _logger.Error(e, "Failed to open URL");
- await _windowService.ShowConfirmContentDialog("Failed to open URL", "We couldn't open the URL for you, check the logs for more details", "Confirm", null);
- }
- }
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/VisualScripting/NodeScriptView.axaml.cs b/src/Artemis.UI/Screens/VisualScripting/NodeScriptView.axaml.cs
index ea59272a8..f87985bc2 100644
--- a/src/Artemis.UI/Screens/VisualScripting/NodeScriptView.axaml.cs
+++ b/src/Artemis.UI/Screens/VisualScripting/NodeScriptView.axaml.cs
@@ -45,6 +45,7 @@ public class NodeScriptView : ReactiveUserControl
_zoomBorder.AddHandler(PointerWheelChangedEvent, ZoomOnPointerWheelChanged, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble, true);
this.WhenActivated(d =>
{
+ ViewModel.AutoFitRequested += ViewModelOnAutoFitRequested;
ViewModel!.PickerPositionSubject.Subscribe(ShowPickerAt).DisposeWith(d);
if (ViewModel.IsPreview)
{
@@ -53,6 +54,7 @@ public class NodeScriptView : ReactiveUserControl
}
Dispatcher.UIThread.InvokeAsync(() => AutoFit(true), DispatcherPriority.ContextIdle);
+ Disposable.Create(() => ViewModel.AutoFitRequested -= ViewModelOnAutoFitRequested).DisposeWith(d);
});
}
@@ -117,6 +119,11 @@ public class NodeScriptView : ReactiveUserControl
_zoomBorder.Pan(Bounds.Center.X - scriptRect.Center.X * scale, Bounds.Center.Y - scriptRect.Center.Y * scale, skipTransitions);
}
+ private void ViewModelOnAutoFitRequested(object? sender, EventArgs e)
+ {
+ Dispatcher.UIThread.Post(() => AutoFit(false));
+ }
+
private void ZoomBorderOnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property.Name == nameof(_zoomBorder.Background))
@@ -136,6 +143,8 @@ public class NodeScriptView : ReactiveUserControl
private void ZoomBorder_OnZoomChanged(object sender, ZoomChangedEventArgs e)
{
+ if (ViewModel != null)
+ ViewModel.PanMatrix = _zoomBorder.Matrix;
UpdateZoomBorderBackground();
}
diff --git a/src/Artemis.UI/Screens/VisualScripting/NodeScriptViewModel.cs b/src/Artemis.UI/Screens/VisualScripting/NodeScriptViewModel.cs
index 09ff9440b..e73c87cb6 100644
--- a/src/Artemis.UI/Screens/VisualScripting/NodeScriptViewModel.cs
+++ b/src/Artemis.UI/Screens/VisualScripting/NodeScriptViewModel.cs
@@ -30,6 +30,7 @@ public class NodeScriptViewModel : ActivatableViewModelBase
private DragCableViewModel? _dragViewModel;
private List? _initialNodeSelection;
+ private Matrix _panMatrix;
public NodeScriptViewModel(NodeScript nodeScript, bool isPreview, INodeVmFactory nodeVmFactory, INodeService nodeService, INodeEditorService nodeEditorService)
{
@@ -95,6 +96,12 @@ public class NodeScriptViewModel : ActivatableViewModelBase
get => _dragViewModel;
set => RaiseAndSetIfChanged(ref _dragViewModel, value);
}
+
+ public Matrix PanMatrix
+ {
+ get => _panMatrix;
+ set => RaiseAndSetIfChanged(ref _panMatrix, value);
+ }
public void DeleteSelectedNodes()
{
@@ -223,4 +230,11 @@ public class NodeScriptViewModel : ActivatableViewModelBase
if (toRemove != null)
_nodeViewModels.Remove(toRemove);
}
+
+ public void RequestAutoFit()
+ {
+ AutoFitRequested?.Invoke(this, EventArgs.Empty);
+ }
+
+ public event EventHandler? AutoFitRequested;
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowView.axaml b/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowView.axaml
index 55685bd32..8b9a2c801 100644
--- a/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowView.axaml
+++ b/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowView.axaml
@@ -4,18 +4,163 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:visualScripting="clr-namespace:Artemis.UI.Screens.VisualScripting"
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
+ xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
+ xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.VisualScripting.NodeScriptWindowView"
x:DataType="visualScripting:NodeScriptWindowViewModel"
Title="Artemis | Visual Script Editor"
Width="1200"
Height="800">
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
+
diff --git a/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowViewModel.cs b/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowViewModel.cs
index 422cef7cf..e0dabe1da 100644
--- a/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowViewModel.cs
+++ b/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowViewModel.cs
@@ -1,18 +1,122 @@
-using Artemis.Core;
+using System;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.IO;
+using System.Reactive;
+using System.Threading.Tasks;
+using Artemis.Core;
+using Artemis.Core.Services;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Shared;
+using Artemis.UI.Shared.Services;
+using Artemis.UI.Shared.Services.NodeEditor;
+using Artemis.UI.Shared.Services.NodeEditor.Commands;
+using Avalonia;
+using DynamicData;
+using DynamicData.List;
+using ReactiveUI;
-namespace Artemis.UI.Screens.VisualScripting
+namespace Artemis.UI.Screens.VisualScripting;
+
+public class NodeScriptWindowViewModel : DialogViewModelBase
{
- public class NodeScriptWindowViewModel : DialogViewModelBase
- {
- public NodeScript NodeScript { get; }
- public NodeScriptViewModel NodeScriptViewModel { get; set; }
+ private readonly INodeService _nodeService;
+ private readonly INodeEditorService _nodeEditorService;
+ private readonly ISettingsService _settingsService;
+ private readonly IWindowService _windowService;
- public NodeScriptWindowViewModel(NodeScript nodeScript, INodeVmFactory vmFactory)
- {
- NodeScript = nodeScript;
- NodeScriptViewModel = vmFactory.NodeScriptViewModel(NodeScript, false);
- }
+ public NodeScriptWindowViewModel(NodeScript nodeScript,
+ INodeService nodeService,
+ INodeEditorService nodeEditorService,
+ INodeVmFactory vmFactory,
+ ISettingsService settingsService,
+ IWindowService windowService)
+ {
+ NodeScript = nodeScript;
+ NodeScriptViewModel = vmFactory.NodeScriptViewModel(NodeScript, false);
+ OpenUri = ReactiveCommand.Create(s => Process.Start(new ProcessStartInfo(s) {UseShellExecute = true, Verb = "open"}));
+ ToggleBooleanSetting = ReactiveCommand.Create>(ExecuteToggleBooleanSetting);
+ History = nodeEditorService.GetHistory(nodeScript);
+
+ _nodeService = nodeService;
+ _nodeEditorService = nodeEditorService;
+ _settingsService = settingsService;
+ _windowService = windowService;
+
+ SourceList nodeSourceList = new();
+ nodeSourceList.AddRange(nodeService.AvailableNodes);
+ nodeSourceList.Connect()
+ .GroupWithImmutableState(n => n.Category)
+ .Bind(out ReadOnlyObservableCollection> categories)
+ .Subscribe();
+ Categories = categories;
+
+ CreateNode = ReactiveCommand.Create(ExecuteCreateNode);
+ Export = ReactiveCommand.CreateFromTask(ExecuteExport);
+ Import = ReactiveCommand.CreateFromTask(ExecuteImport);
+ }
+
+ public NodeScript NodeScript { get; }
+ public NodeScriptViewModel NodeScriptViewModel { get; set; }
+
+ public NodeEditorHistory History { get; }
+ public ReactiveCommand, Unit> ToggleBooleanSetting { get; set; }
+ public ReactiveCommand OpenUri { get; set; }
+ public ReadOnlyObservableCollection> Categories { get; }
+ public ReactiveCommand CreateNode { get; }
+ public ReactiveCommand Export { get; }
+ public ReactiveCommand Import { get; }
+
+ public PluginSetting ShowDataModelValues => _settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false);
+ public PluginSetting ShowFullPaths => _settingsService.GetSetting("ProfileEditor.ShowFullPaths", false);
+ public PluginSetting AlwaysShowValues => _settingsService.GetSetting("ProfileEditor.AlwaysShowValues", false);
+
+ private void ExecuteToggleBooleanSetting(PluginSetting setting)
+ {
+ setting.Value = !setting.Value;
+ setting.Save();
+ }
+
+ private void ExecuteCreateNode(NodeData data)
+ {
+ // Place the node in the top-left of the canvas, keeping in mind the user may have panned
+ INode node = data.CreateNode(NodeScript, null);
+ Point point = new Point(0, 0).Transform(NodeScriptViewModel.PanMatrix.Invert());
+
+ node.X = Math.Round(point.X / 10d, 0, MidpointRounding.AwayFromZero) * 10d + 20;
+ node.Y = Math.Round(point.Y / 10d, 0, MidpointRounding.AwayFromZero) * 10d + 20;
+
+ _nodeEditorService.ExecuteCommand(NodeScript, new AddNode(NodeScript, node));
+ }
+
+ private async Task ExecuteExport()
+ {
+ // Might not cover everything but then the dialog will complain and that's good enough
+ string? result = await _windowService.CreateSaveFileDialog()
+ .HavingFilter(f => f.WithExtension("json").WithName("Artemis node script"))
+ .ShowAsync();
+
+ if (result == null)
+ return;
+
+ string json = _nodeService.ExportScript(NodeScript);
+ await File.WriteAllTextAsync(result, json);
+ }
+
+ private async Task ExecuteImport()
+ {
+ string[]? result = await _windowService.CreateOpenFileDialog()
+ .HavingFilter(f => f.WithExtension("json").WithName("Artemis node script"))
+ .ShowAsync();
+
+ if (result == null)
+ return;
+
+ string json = await File.ReadAllTextAsync(result[0]);
+ _nodeService.ImportScript(json, NodeScript);
+ History.Clear();
+
+ await Task.Delay(200);
+ NodeScriptViewModel.RequestAutoFit();
}
}
\ No newline at end of file
diff --git a/src/Artemis.VisualScripting/Nodes/Operators/Screens/EnumEqualsNodeCustomViewModel.cs b/src/Artemis.VisualScripting/Nodes/Operators/Screens/EnumEqualsNodeCustomViewModel.cs
index 469506c50..16fad79e2 100644
--- a/src/Artemis.VisualScripting/Nodes/Operators/Screens/EnumEqualsNodeCustomViewModel.cs
+++ b/src/Artemis.VisualScripting/Nodes/Operators/Screens/EnumEqualsNodeCustomViewModel.cs
@@ -27,7 +27,8 @@ public class EnumEqualsNodeCustomViewModel : CustomNodeViewModel
if (_node.InputPin.ConnectedTo.Any())
{
EnumValues.Clear();
- EnumValues.AddRange(Enum.GetValues(_node.InputPin.ConnectedTo.First().Type).Cast());
+ if (_node.InputPin.ConnectedTo.First().Type.IsEnum)
+ EnumValues.AddRange(Enum.GetValues(_node.InputPin.ConnectedTo.First().Type).Cast());
this.RaisePropertyChanged(nameof(CurrentValue));
}