diff --git a/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs b/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs
index e832df0b9..e5da142a7 100644
--- a/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs
+++ b/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs
@@ -11,17 +11,15 @@ namespace Artemis.Core.Services;
internal class ProcessMonitorService : IProcessMonitorService
{
private readonly ProcessComparer _comparer;
- private readonly ILogger _logger;
private Process[] _lastScannedProcesses;
- public ProcessMonitorService(ILogger logger)
+ public ProcessMonitorService()
{
- _logger = logger;
+ _comparer = new ProcessComparer();
_lastScannedProcesses = Process.GetProcesses();
Timer processScanTimer = new(1000);
processScanTimer.Elapsed += OnTimerElapsed;
processScanTimer.Start();
- _comparer = new ProcessComparer();
ProcessActivationRequirement.ProcessMonitorService = this;
}
@@ -30,16 +28,9 @@ internal class ProcessMonitorService : IProcessMonitorService
{
Process[] newProcesses = Process.GetProcesses();
foreach (Process startedProcess in newProcesses.Except(_lastScannedProcesses, _comparer))
- {
ProcessStarted?.Invoke(this, new ProcessEventArgs(startedProcess));
- //_logger.Verbose("Started Process: {startedProcess}", startedProcess.ProcessName);
- }
-
foreach (Process stoppedProcess in _lastScannedProcesses.Except(newProcesses, _comparer))
- {
ProcessStopped?.Invoke(this, new ProcessEventArgs(stoppedProcess));
- //_logger.Verbose("Stopped Process: {stoppedProcess}", stoppedProcess.ProcessName);
- }
_lastScannedProcesses = newProcesses;
}
diff --git a/src/Artemis.Core/VisualScripting/Interfaces/INodeScript.cs b/src/Artemis.Core/VisualScripting/Interfaces/INodeScript.cs
index c45fbdb96..456692a4d 100644
--- a/src/Artemis.Core/VisualScripting/Interfaces/INodeScript.cs
+++ b/src/Artemis.Core/VisualScripting/Interfaces/INodeScript.cs
@@ -8,7 +8,7 @@ namespace Artemis.Core;
///
/// Represents a node script
///
-public interface INodeScript : INotifyPropertyChanged, IDisposable
+public interface INodeScript : INotifyPropertyChanged, IDisposable, IStorageModel
{
///
/// Gets the name of the node script.
@@ -66,6 +66,11 @@ public interface INodeScript : INotifyPropertyChanged, IDisposable
///
/// The node to remove
void RemoveNode(INode node);
+
+ ///
+ /// Loads missing connections between the nodes of this node script from storage
+ ///
+ void LoadConnections();
}
///
diff --git a/src/Artemis.Core/VisualScripting/NodeScript.cs b/src/Artemis.Core/VisualScripting/NodeScript.cs
index ce6a7af00..8abc29fbd 100644
--- a/src/Artemis.Core/VisualScripting/NodeScript.cs
+++ b/src/Artemis.Core/VisualScripting/NodeScript.cs
@@ -12,7 +12,7 @@ namespace Artemis.Core;
///
/// Represents a node script
///
-public abstract class NodeScript : CorePropertyChanged, INodeScript, IStorageModel
+public abstract class NodeScript : CorePropertyChanged, INodeScript
{
private void NodeTypeStoreOnNodeTypeChanged(object? sender, NodeTypeStoreEvent e)
{
@@ -226,9 +226,7 @@ public abstract class NodeScript : CorePropertyChanged, INodeScript, IStorageMod
return node;
}
- ///
- /// Loads missing connections between the nodes of this node script from the
- ///
+ ///
public void LoadConnections()
{
List nodes = Nodes.ToList();
diff --git a/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs b/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs
index c903a1d84..26c5c36ed 100644
--- a/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs
+++ b/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs
@@ -33,12 +33,14 @@ public class LinuxInputProvider : InputProvider
protected override void Dispose(bool disposing)
{
if (disposing)
+ {
for (int i = _readers.Count - 1; i >= 0; i--)
{
_readers[i].InputEvent -= OnInputEvent;
_readers[i].Dispose();
_readers.RemoveAt(i);
}
+ }
base.Dispose(disposing);
}
@@ -49,6 +51,7 @@ public class LinuxInputProvider : InputProvider
{
if (sender is not LinuxInputDeviceReader reader)
return;
+
switch (reader.InputDevice.DeviceType)
{
case LinuxDeviceType.Keyboard:
@@ -64,40 +67,34 @@ public class LinuxInputProvider : InputProvider
private void HandleKeyboardData(LinuxInputDevice keyboard, LinuxInputEventArgs args)
{
- switch (args.Type)
+ if (args.Type != LinuxInputEventType.KEY)
+ return;
+
+ KeyboardKey key = InputUtilities.KeyFromKeyCode((LinuxKeyboardKeyCodes) args.Code);
+ bool isDown = args.Value != 0;
+
+ //_logger.Verbose($"Keyboard Key: {(LinuxKeyboardKeyCodes)args.Code} | Down: {isDown}");
+
+ LinuxInputDevice.LinuxInputId identifier = keyboard.InputId;
+ OnIdentifierReceived(identifier, InputDeviceType.Keyboard);
+ ArtemisDevice? device = null;
+
+ try
{
- case LinuxInputEventType.KEY:
- KeyboardKey key = InputUtilities.KeyFromKeyCode((LinuxKeyboardKeyCodes) args.Code);
- bool isDown = args.Value != 0;
-
- //_logger.Verbose($"Keyboard Key: {(LinuxKeyboardKeyCodes)args.Code} | Down: {isDown}");
-
- LinuxInputDevice.LinuxInputId identifier = keyboard.InputId;
-
- OnIdentifierReceived(identifier, InputDeviceType.Keyboard);
-
- ArtemisDevice? device = null;
-
- try
- {
- device = _inputService.GetDeviceByIdentifier(this, identifier, InputDeviceType.Keyboard);
- }
- catch (Exception e)
- {
- _logger.Warning(e, "Failed to retrieve input device by its identifier");
- }
-
- OnKeyboardDataReceived(device, key, isDown);
- break;
+ device = _inputService.GetDeviceByIdentifier(this, identifier, InputDeviceType.Keyboard);
}
+ catch (Exception e)
+ {
+ _logger.Warning(e, "Failed to retrieve input device by its identifier");
+ }
+
+ OnKeyboardDataReceived(device, key, isDown);
}
private void HandleMouseData(LinuxInputDevice mouse, LinuxInputEventArgs args)
{
LinuxInputDevice.LinuxInputId identifier = mouse.InputId;
-
OnIdentifierReceived(identifier, InputDeviceType.Mouse);
-
ArtemisDevice? device = null;
try
@@ -112,13 +109,11 @@ public class LinuxInputProvider : InputProvider
switch (args.Type)
{
case LinuxInputEventType.KEY:
- var key = (LinuxKeyboardKeyCodes)args.Code;
- if (key == LinuxKeyboardKeyCodes.BTN_TOUCH ||
+ LinuxKeyboardKeyCodes key = (LinuxKeyboardKeyCodes) args.Code;
+ if (key == LinuxKeyboardKeyCodes.BTN_TOUCH ||
(key >= LinuxKeyboardKeyCodes.BTN_TOOL_PEN && key <= LinuxKeyboardKeyCodes.BTN_TOOL_QUADTAP))
- {
//trackpad input, ignore.
return;
- }
//0 - up
//1 - down
diff --git a/src/Artemis.UI.Shared/Services/NodeEditor/Commands/ConnectPins.cs b/src/Artemis.UI.Shared/Services/NodeEditor/Commands/ConnectPins.cs
index c7b01be05..0b65a56e1 100644
--- a/src/Artemis.UI.Shared/Services/NodeEditor/Commands/ConnectPins.cs
+++ b/src/Artemis.UI.Shared/Services/NodeEditor/Commands/ConnectPins.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Linq;
using Artemis.Core;
namespace Artemis.UI.Shared.Services.NodeEditor.Commands;
@@ -8,9 +9,9 @@ namespace Artemis.UI.Shared.Services.NodeEditor.Commands;
///
public class ConnectPins : INodeEditorCommand
{
- private readonly List? _originalConnections;
- private readonly IPin _source;
- private readonly IPin _target;
+ private readonly IPin _output;
+ private readonly IPin _input;
+ private readonly IPin? _originalConnection;
///
/// Creates a new instance of the class.
@@ -19,10 +20,18 @@ public class ConnectPins : INodeEditorCommand
/// The target of the connection.
public ConnectPins(IPin source, IPin target)
{
- _source = source;
- _target = target;
+ if (source.Direction == PinDirection.Output)
+ {
+ _output = source;
+ _input = target;
+ }
+ else
+ {
+ _output = target;
+ _input = source;
+ }
- _originalConnections = _target.Direction == PinDirection.Input ? new List(_target.ConnectedTo) : null;
+ _originalConnection = _input.ConnectedTo.FirstOrDefault();
}
#region Implementation of INodeEditorCommand
@@ -33,20 +42,16 @@ public class ConnectPins : INodeEditorCommand
///
public void Execute()
{
- if (_target.Direction == PinDirection.Input)
- _target.DisconnectAll();
- _source.ConnectTo(_target);
+ _input.DisconnectAll();
+ _output.ConnectTo(_input);
}
///
public void Undo()
{
- _target.DisconnectFrom(_source);
-
- if (_originalConnections == null)
- return;
- foreach (IPin pin in _originalConnections)
- _target.ConnectTo(pin);
+ _input.DisconnectAll();
+ if (_originalConnection != null)
+ _input.ConnectTo(_originalConnection);
}
#endregion
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingViewModel.cs
index 9000af7e3..eb1dd81e5 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingViewModel.cs
@@ -25,6 +25,7 @@ public class DataBindingViewModel : ActivatableViewModelBase
private ObservableAsPropertyHelper? _layerProperty;
private ObservableAsPropertyHelper? _nodeScriptViewModel;
private bool _playing;
+ private bool _editorOpen;
public DataBindingViewModel(IProfileEditorService profileEditorService, INodeVmFactory nodeVmFactory, IWindowService windowService, ISettingsService settingsService)
{
@@ -49,11 +50,18 @@ public class DataBindingViewModel : ActivatableViewModelBase
.DisposeWith(d);
_profileEditorService.Playing.CombineLatest(_profileEditorService.SuspendedEditing).Subscribe(tuple => _playing = tuple.First || tuple.Second).DisposeWith(d);
- DispatcherTimer updateTimer = new(TimeSpan.FromMilliseconds(60.0 / 1000), DispatcherPriority.Render, Update);
+ DispatcherTimer updateTimer = new(TimeSpan.FromMilliseconds(25.0 / 1000), DispatcherPriority.Render, Update);
+ // TODO: Remove in favor of saving each time a node editor command is executed
+ DispatcherTimer saveTimer = new(TimeSpan.FromMinutes(2), DispatcherPriority.Normal, Save);
+
updateTimer.Start();
+ saveTimer.Start();
+
Disposable.Create(() =>
{
updateTimer.Stop();
+ saveTimer.Stop();
+
_profileEditorService.SaveProfile();
}).DisposeWith(d);
});
@@ -74,11 +82,19 @@ public class DataBindingViewModel : ActivatableViewModelBase
public async Task OpenEditor()
{
- if (LayerProperty != null && LayerProperty.BaseDataBinding.IsEnabled)
+ if (LayerProperty == null || !LayerProperty.BaseDataBinding.IsEnabled)
+ return;
+
+ try
{
+ _editorOpen = true;
await _windowService.ShowDialogAsync(("nodeScript", LayerProperty.BaseDataBinding.Script));
await _profileEditorService.SaveProfileAsync();
}
+ finally
+ {
+ _editorOpen = false;
+ }
}
private void Update(object? sender, EventArgs e)
@@ -89,4 +105,10 @@ public class DataBindingViewModel : ActivatableViewModelBase
LayerProperty?.UpdateDataBinding();
}
+
+ private void Save(object? sender, EventArgs e)
+ {
+ if (!_editorOpen)
+ _profileEditorService.SaveProfile();
+ }
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowViewModel.cs b/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowViewModel.cs
index c71578605..09dc7d049 100644
--- a/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowViewModel.cs
+++ b/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowViewModel.cs
@@ -12,6 +12,7 @@ using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.NodeEditor;
using Artemis.UI.Shared.Services.NodeEditor.Commands;
+using Artemis.UI.Shared.Services.ProfileEditor;
using Avalonia;
using Avalonia.Threading;
using DynamicData;
@@ -25,6 +26,7 @@ public class NodeScriptWindowViewModel : DialogViewModelBase
private readonly INodeEditorService _nodeEditorService;
private readonly INodeService _nodeService;
private readonly ISettingsService _settingsService;
+ private readonly IProfileService _profileService;
private readonly IWindowService _windowService;
public NodeScriptWindowViewModel(NodeScript nodeScript,
@@ -32,6 +34,7 @@ public class NodeScriptWindowViewModel : DialogViewModelBase
INodeEditorService nodeEditorService,
INodeVmFactory vmFactory,
ISettingsService settingsService,
+ IProfileService profileService,
IWindowService windowService)
{
NodeScript = nodeScript;
@@ -43,6 +46,7 @@ public class NodeScriptWindowViewModel : DialogViewModelBase
_nodeService = nodeService;
_nodeEditorService = nodeEditorService;
_settingsService = settingsService;
+ _profileService = profileService;
_windowService = windowService;
SourceList nodeSourceList = new();
@@ -60,8 +64,17 @@ public class NodeScriptWindowViewModel : DialogViewModelBase
this.WhenActivated(d =>
{
DispatcherTimer updateTimer = new(TimeSpan.FromMilliseconds(25.0 / 1000), DispatcherPriority.Normal, Update);
+ // TODO: Remove in favor of saving each time a node editor command is executed
+ DispatcherTimer saveTimer = new(TimeSpan.FromMinutes(2), DispatcherPriority.Normal, Save);
+
updateTimer.Start();
- Disposable.Create(() => updateTimer.Stop()).DisposeWith(d);
+ saveTimer.Start();
+
+ Disposable.Create(() =>
+ {
+ updateTimer.Stop();
+ saveTimer.Stop();
+ }).DisposeWith(d);
});
}
@@ -133,4 +146,10 @@ public class NodeScriptWindowViewModel : DialogViewModelBase
{
NodeScript.Run();
}
+
+ private void Save(object? sender, EventArgs e)
+ {
+ if (NodeScript.Context is Profile profile)
+ _profileService.SaveProfile(profile, true);
+ }
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/VisualScripting/NodeViewModel.cs b/src/Artemis.UI/Screens/VisualScripting/NodeViewModel.cs
index 5631a38be..bb3a1670d 100644
--- a/src/Artemis.UI/Screens/VisualScripting/NodeViewModel.cs
+++ b/src/Artemis.UI/Screens/VisualScripting/NodeViewModel.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.ObjectModel;
+using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using Artemis.Core;
@@ -41,44 +42,23 @@ public class NodeViewModel : ActivatableViewModelBase
DeleteNode = ReactiveCommand.Create(ExecuteDeleteNode, this.WhenAnyValue(vm => vm.IsStaticNode).Select(v => !v));
- SourceList nodePins = new();
- SourceList nodePinCollections = new();
+ SourceList nodePins = new();
+ SourceList nodePinCollections = new();
// Create observable collections split up by direction
- nodePins.Connect()
- .Filter(n => n.Direction == PinDirection.Input)
- .Transform(p => (PinViewModel) nodeVmFactory.InputPinViewModel(p, nodeScriptViewModel))
- .Bind(out ReadOnlyObservableCollection inputPins)
- .Subscribe();
- nodePins.Connect()
- .Filter(n => n.Direction == PinDirection.Output)
- .Transform(p => (PinViewModel) nodeVmFactory.OutputPinViewModel(p, nodeScriptViewModel))
- .Bind(out ReadOnlyObservableCollection outputPins)
- .Subscribe();
+ nodePins.Connect().Filter(n => n.Pin.Direction == PinDirection.Input).Bind(out ReadOnlyObservableCollection inputPins).Subscribe();
+ nodePins.Connect().Filter(n => n.Pin.Direction == PinDirection.Output).Bind(out ReadOnlyObservableCollection outputPins).Subscribe();
InputPinViewModels = inputPins;
OutputPinViewModels = outputPins;
// Same again but for pin collections
- nodePinCollections.Connect()
- .Filter(n => n.Direction == PinDirection.Input)
- .Transform(c => (PinCollectionViewModel) nodeVmFactory.InputPinCollectionViewModel(c, nodeScriptViewModel))
- .Bind(out ReadOnlyObservableCollection inputPinCollections)
- .Subscribe();
- nodePinCollections.Connect()
- .Filter(n => n.Direction == PinDirection.Output)
- .Transform(c => (PinCollectionViewModel) nodeVmFactory.OutputPinCollectionViewModel(c, nodeScriptViewModel))
- .Bind(out ReadOnlyObservableCollection outputPinCollections)
- .Subscribe();
+ nodePinCollections.Connect().Filter(n => n.PinCollection.Direction == PinDirection.Input).Bind(out ReadOnlyObservableCollection inputPinCollections).Subscribe();
+ nodePinCollections.Connect().Filter(n => n.PinCollection.Direction == PinDirection.Output).Bind(out ReadOnlyObservableCollection outputPinCollections).Subscribe();
InputPinCollectionViewModels = inputPinCollections;
OutputPinCollectionViewModels = outputPinCollections;
// Create a single observable collection containing all pin view models
- InputPinViewModels.ToObservableChangeSet()
- .Merge(OutputPinViewModels.ToObservableChangeSet())
- .Merge(InputPinCollectionViewModels.ToObservableChangeSet().TransformMany(c => c.PinViewModels))
- .Merge(OutputPinCollectionViewModels.ToObservableChangeSet().TransformMany(c => c.PinViewModels))
- .Bind(out ReadOnlyObservableCollection pins)
- .Subscribe();
+ nodePins.Connect().Merge(nodePinCollections.Connect().TransformMany(c => c.PinViewModels)).Bind(out ReadOnlyObservableCollection pins).Subscribe();
PinViewModels = pins;
@@ -101,30 +81,54 @@ public class NodeViewModel : ActivatableViewModelBase
// Subscribe to pin changes
Observable.FromEventPattern>(x => Node.PinAdded += x, x => Node.PinAdded -= x)
- .Subscribe(p => nodePins.Add(p.EventArgs.Value))
+ .Subscribe(p =>
+ {
+ if (p.EventArgs.Value.Direction == PinDirection.Input)
+ nodePins.Add(nodeVmFactory.InputPinViewModel(p.EventArgs.Value, nodeScriptViewModel));
+ else
+ nodePins.Add(nodeVmFactory.OutputPinViewModel(p.EventArgs.Value, nodeScriptViewModel));
+ })
.DisposeWith(d);
Observable.FromEventPattern>(x => Node.PinRemoved += x, x => Node.PinRemoved -= x)
- .Subscribe(p => nodePins.Remove(p.EventArgs.Value))
+ .Subscribe(p => nodePins!.Remove(nodePins.Items.FirstOrDefault(vm => vm.Pin == p.EventArgs.Value)))
.DisposeWith(d);
nodePins.Edit(l =>
{
l.Clear();
- l.AddRange(Node.Pins);
+ foreach (IPin nodePin in Node.Pins)
+ {
+ if (nodePin.Direction == PinDirection.Input)
+ l.Add(nodeVmFactory.InputPinViewModel(nodePin, nodeScriptViewModel));
+ else
+ l.Add(nodeVmFactory.OutputPinViewModel(nodePin, nodeScriptViewModel));
+ }
});
-
+
// Subscribe to pin collection changes
Observable.FromEventPattern>(x => Node.PinCollectionAdded += x, x => Node.PinCollectionAdded -= x)
- .Subscribe(p => nodePinCollections.Add(p.EventArgs.Value))
+ .Subscribe(p =>
+ {
+ if (p.EventArgs.Value.Direction == PinDirection.Input)
+ nodeVmFactory.InputPinCollectionViewModel(p.EventArgs.Value, nodeScriptViewModel);
+ else
+ nodeVmFactory.OutputPinCollectionViewModel(p.EventArgs.Value, nodeScriptViewModel);
+ })
.DisposeWith(d);
Observable.FromEventPattern>(x => Node.PinCollectionRemoved += x, x => Node.PinCollectionRemoved -= x)
- .Subscribe(p => nodePinCollections.Remove(p.EventArgs.Value))
+ .Subscribe(p => nodePinCollections!.Remove(nodePinCollections.Items.FirstOrDefault(vm => vm.PinCollection == p.EventArgs.Value)))
.DisposeWith(d);
nodePinCollections.Edit(l =>
{
l.Clear();
- l.AddRange(Node.PinCollections);
+ foreach (IPinCollection nodePinCollection in Node.PinCollections)
+ {
+ if (nodePinCollection.Direction == PinDirection.Input)
+ l.Add(nodeVmFactory.InputPinCollectionViewModel(nodePinCollection, nodeScriptViewModel));
+ else
+ l.Add(nodeVmFactory.OutputPinCollectionViewModel(nodePinCollection, nodeScriptViewModel));
+ }
});
-
+
if (Node is Node coreNode)
CustomNodeViewModel = coreNode.GetCustomViewModel(nodeScriptViewModel.NodeScript);
});
diff --git a/src/Artemis.VisualScripting/Nodes/Branching/EnumSwitchNode.cs b/src/Artemis.VisualScripting/Nodes/Branching/EnumSwitchNode.cs
new file mode 100644
index 000000000..f94911661
--- /dev/null
+++ b/src/Artemis.VisualScripting/Nodes/Branching/EnumSwitchNode.cs
@@ -0,0 +1,97 @@
+using Artemis.Core;
+using Artemis.Core.Events;
+using Humanizer;
+
+namespace Artemis.VisualScripting.Nodes.Branching;
+
+[Node("Switch (Enum)", "Outputs the input that corresponds to the switch value", "Operators", InputType = typeof(Enum), OutputType = typeof(object))]
+public class EnumSwitchNode : Node
+{
+ private readonly Dictionary _inputPins;
+
+ public EnumSwitchNode() : base("Enum Branch", "desc")
+ {
+ _inputPins = new Dictionary();
+
+ Output = CreateOutputPin(typeof(object), "Result");
+ SwitchValue = CreateInputPin("Switch");
+
+ SwitchValue.PinConnected += OnSwitchPinConnected;
+ SwitchValue.PinDisconnected += OnSwitchPinDisconnected;
+ }
+
+ public OutputPin Output { get; }
+ public InputPin SwitchValue { get; }
+
+ public override void Evaluate()
+ {
+ if (SwitchValue.Value is null)
+ {
+ Output.Value = null;
+ return;
+ }
+
+ if (!_inputPins.TryGetValue(SwitchValue.Value, out InputPin? pin))
+ {
+ Output.Value = null;
+ return;
+ }
+
+ if (pin.ConnectedTo.Count == 0)
+ {
+ Output.Value = null;
+ return;
+ }
+
+ Output.Value = pin.Value;
+ }
+
+ private void OnInputPinDisconnected(object? sender, SingleValueEventArgs e)
+ {
+ // if this is the last pin to disconnect, reset the type.
+ if (_inputPins.Values.All(i => i.ConnectedTo.Count == 0))
+ ChangeType(typeof(object));
+ }
+
+ private void OnInputPinConnected(object? sender, SingleValueEventArgs e)
+ {
+ // change the type of our inputs and output
+ // depending on the first node the user connects to
+ ChangeType(e.Value.Type);
+ }
+
+ private void OnSwitchPinConnected(object? sender, SingleValueEventArgs e)
+ {
+ if (SwitchValue.ConnectedTo.Count == 0)
+ return;
+
+ Type enumType = SwitchValue.ConnectedTo[0].Type;
+ foreach (Enum enumValue in Enum.GetValues(enumType).Cast())
+ {
+ InputPin pin = CreateOrAddInputPin(typeof(object), enumValue.ToString().Humanize(LetterCasing.Sentence));
+ pin.PinConnected += OnInputPinConnected;
+ pin.PinDisconnected += OnInputPinDisconnected;
+ _inputPins[enumValue] = pin;
+ }
+ }
+
+ private void OnSwitchPinDisconnected(object? sender, SingleValueEventArgs e)
+ {
+ foreach (InputPin input in _inputPins.Values)
+ {
+ input.PinConnected -= OnInputPinConnected;
+ input.PinDisconnected -= OnInputPinDisconnected;
+ RemovePin(input);
+ }
+
+ _inputPins.Clear();
+ ChangeType(typeof(object));
+ }
+
+ private void ChangeType(Type type)
+ {
+ foreach (InputPin input in _inputPins.Values)
+ input.ChangeType(type);
+ Output.ChangeType(type);
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.VisualScripting/Nodes/DataModel/DataModelEventCycleNode.cs b/src/Artemis.VisualScripting/Nodes/DataModel/DataModelEventCycleNode.cs
index cab064242..a5de87de0 100644
--- a/src/Artemis.VisualScripting/Nodes/DataModel/DataModelEventCycleNode.cs
+++ b/src/Artemis.VisualScripting/Nodes/DataModel/DataModelEventCycleNode.cs
@@ -48,9 +48,7 @@ public class DataModelEventCycleNode : Node propertyAccessor, OutputPin outputPin) in _propertyPins)
+ {
+ if (!outputPin.ConnectedTo.Any())
+ continue;
+ object value = dataModelEvent.LastEventArgumentsUntyped != null ? propertyAccessor(dataModelEvent.LastEventArgumentsUntyped) : outputPin.Type.GetDefault()!;
+ outputPin.Value = outputPin.IsNumeric ? new Numeric(value) : value;
+ }
+ }
+
+ private void UpdateDataModelPath()
+ {
+ DataModelPath? old = _dataModelPath;
+ _dataModelPath = Storage != null ? new DataModelPath(Storage) : null;
+ if (_dataModelPath != null)
+ _dataModelPath.PathValidated += DataModelPathOnPathValidated;
+
+ if (old != null)
+ {
+ old.PathValidated -= DataModelPathOnPathValidated;
+ old.Dispose();
+ }
+
+ UpdateOutputPins();
+ }
+
+ private void UpdateOutputPins()
+ {
+ object? pathValue = _dataModelPath?.GetValue();
+ if (pathValue is IDataModelEvent dataModelEvent)
+ CreatePins(dataModelEvent);
+ }
+
private void CreatePins(IDataModelEvent? dataModelEvent)
{
if (_dataModelEvent == dataModelEvent)
@@ -72,34 +112,12 @@ public class DataModelEventNode : Node propertyAccessor, OutputPin outputPin) in _propertyPins)
- {
- if (!outputPin.ConnectedTo.Any())
- continue;
- object value = dataModelEvent.LastEventArgumentsUntyped != null ? propertyAccessor(dataModelEvent.LastEventArgumentsUntyped) : outputPin.Type.GetDefault()!;
- outputPin.Value = outputPin.IsNumeric ? new Numeric(value) : value;
- }
- }
-
- private void UpdateDataModelPath()
- {
- DataModelPath? old = _dataModelPath;
- _dataModelPath = Storage != null ? new DataModelPath(Storage) : null;
- old?.Dispose();
-
- object? pathValue = _dataModelPath?.GetValue();
- if (pathValue is IDataModelEvent dataModelEvent)
- CreatePins(dataModelEvent);
+ // Update the output pin now that the type is known and attempt to restore the connection that was likely missing
+ UpdateOutputPins();
+ Script?.LoadConnections();
}
///
diff --git a/src/Artemis.VisualScripting/Nodes/DataModel/DataModelNode.cs b/src/Artemis.VisualScripting/Nodes/DataModel/DataModelNode.cs
index 411f7c1f1..3c3054e1e 100644
--- a/src/Artemis.VisualScripting/Nodes/DataModel/DataModelNode.cs
+++ b/src/Artemis.VisualScripting/Nodes/DataModel/DataModelNode.cs
@@ -1,7 +1,6 @@
using Artemis.Core;
using Artemis.Storage.Entities.Profile;
using Artemis.VisualScripting.Nodes.DataModel.Screens;
-using Avalonia.Threading;
namespace Artemis.VisualScripting.Nodes.DataModel;
@@ -61,17 +60,24 @@ public class DataModelNode : Node