mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-01-01 18:23:32 +00:00
Nodes - Added Enum Switch node
Nodes editor - Rewrite the way pin VMs are constructed
This commit is contained in:
parent
1b5101dc27
commit
0120f37c93
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
@ -41,44 +42,23 @@ public class NodeViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
DeleteNode = ReactiveCommand.Create(ExecuteDeleteNode, this.WhenAnyValue(vm => vm.IsStaticNode).Select(v => !v));
|
DeleteNode = ReactiveCommand.Create(ExecuteDeleteNode, this.WhenAnyValue(vm => vm.IsStaticNode).Select(v => !v));
|
||||||
|
|
||||||
SourceList<IPin> nodePins = new();
|
SourceList<PinViewModel> nodePins = new();
|
||||||
SourceList<IPinCollection> nodePinCollections = new();
|
SourceList<PinCollectionViewModel> nodePinCollections = new();
|
||||||
|
|
||||||
// Create observable collections split up by direction
|
// Create observable collections split up by direction
|
||||||
nodePins.Connect()
|
nodePins.Connect().Filter(n => n.Pin.Direction == PinDirection.Input).Bind(out ReadOnlyObservableCollection<PinViewModel> inputPins).Subscribe();
|
||||||
.Filter(n => n.Direction == PinDirection.Input)
|
nodePins.Connect().Filter(n => n.Pin.Direction == PinDirection.Output).Bind(out ReadOnlyObservableCollection<PinViewModel> outputPins).Subscribe();
|
||||||
.Transform(p => (PinViewModel) nodeVmFactory.InputPinViewModel(p, nodeScriptViewModel))
|
|
||||||
.Bind(out ReadOnlyObservableCollection<PinViewModel> inputPins)
|
|
||||||
.Subscribe();
|
|
||||||
nodePins.Connect()
|
|
||||||
.Filter(n => n.Direction == PinDirection.Output)
|
|
||||||
.Transform(p => (PinViewModel) nodeVmFactory.OutputPinViewModel(p, nodeScriptViewModel))
|
|
||||||
.Bind(out ReadOnlyObservableCollection<PinViewModel> outputPins)
|
|
||||||
.Subscribe();
|
|
||||||
InputPinViewModels = inputPins;
|
InputPinViewModels = inputPins;
|
||||||
OutputPinViewModels = outputPins;
|
OutputPinViewModels = outputPins;
|
||||||
|
|
||||||
// Same again but for pin collections
|
// Same again but for pin collections
|
||||||
nodePinCollections.Connect()
|
nodePinCollections.Connect().Filter(n => n.PinCollection.Direction == PinDirection.Input).Bind(out ReadOnlyObservableCollection<PinCollectionViewModel> inputPinCollections).Subscribe();
|
||||||
.Filter(n => n.Direction == PinDirection.Input)
|
nodePinCollections.Connect().Filter(n => n.PinCollection.Direction == PinDirection.Output).Bind(out ReadOnlyObservableCollection<PinCollectionViewModel> outputPinCollections).Subscribe();
|
||||||
.Transform(c => (PinCollectionViewModel) nodeVmFactory.InputPinCollectionViewModel(c, nodeScriptViewModel))
|
|
||||||
.Bind(out ReadOnlyObservableCollection<PinCollectionViewModel> inputPinCollections)
|
|
||||||
.Subscribe();
|
|
||||||
nodePinCollections.Connect()
|
|
||||||
.Filter(n => n.Direction == PinDirection.Output)
|
|
||||||
.Transform(c => (PinCollectionViewModel) nodeVmFactory.OutputPinCollectionViewModel(c, nodeScriptViewModel))
|
|
||||||
.Bind(out ReadOnlyObservableCollection<PinCollectionViewModel> outputPinCollections)
|
|
||||||
.Subscribe();
|
|
||||||
InputPinCollectionViewModels = inputPinCollections;
|
InputPinCollectionViewModels = inputPinCollections;
|
||||||
OutputPinCollectionViewModels = outputPinCollections;
|
OutputPinCollectionViewModels = outputPinCollections;
|
||||||
|
|
||||||
// Create a single observable collection containing all pin view models
|
// Create a single observable collection containing all pin view models
|
||||||
InputPinViewModels.ToObservableChangeSet()
|
nodePins.Connect().Merge(nodePinCollections.Connect().TransformMany(c => c.PinViewModels)).Bind(out ReadOnlyObservableCollection<PinViewModel> pins).Subscribe();
|
||||||
.Merge(OutputPinViewModels.ToObservableChangeSet())
|
|
||||||
.Merge(InputPinCollectionViewModels.ToObservableChangeSet().TransformMany(c => c.PinViewModels))
|
|
||||||
.Merge(OutputPinCollectionViewModels.ToObservableChangeSet().TransformMany(c => c.PinViewModels))
|
|
||||||
.Bind(out ReadOnlyObservableCollection<PinViewModel> pins)
|
|
||||||
.Subscribe();
|
|
||||||
|
|
||||||
PinViewModels = pins;
|
PinViewModels = pins;
|
||||||
|
|
||||||
@ -101,30 +81,54 @@ public class NodeViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
// Subscribe to pin changes
|
// Subscribe to pin changes
|
||||||
Observable.FromEventPattern<SingleValueEventArgs<IPin>>(x => Node.PinAdded += x, x => Node.PinAdded -= x)
|
Observable.FromEventPattern<SingleValueEventArgs<IPin>>(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);
|
.DisposeWith(d);
|
||||||
Observable.FromEventPattern<SingleValueEventArgs<IPin>>(x => Node.PinRemoved += x, x => Node.PinRemoved -= x)
|
Observable.FromEventPattern<SingleValueEventArgs<IPin>>(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);
|
.DisposeWith(d);
|
||||||
nodePins.Edit(l =>
|
nodePins.Edit(l =>
|
||||||
{
|
{
|
||||||
l.Clear();
|
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
|
// Subscribe to pin collection changes
|
||||||
Observable.FromEventPattern<SingleValueEventArgs<IPinCollection>>(x => Node.PinCollectionAdded += x, x => Node.PinCollectionAdded -= x)
|
Observable.FromEventPattern<SingleValueEventArgs<IPinCollection>>(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);
|
.DisposeWith(d);
|
||||||
Observable.FromEventPattern<SingleValueEventArgs<IPinCollection>>(x => Node.PinCollectionRemoved += x, x => Node.PinCollectionRemoved -= x)
|
Observable.FromEventPattern<SingleValueEventArgs<IPinCollection>>(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);
|
.DisposeWith(d);
|
||||||
nodePinCollections.Edit(l =>
|
nodePinCollections.Edit(l =>
|
||||||
{
|
{
|
||||||
l.Clear();
|
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)
|
if (Node is Node coreNode)
|
||||||
CustomNodeViewModel = coreNode.GetCustomViewModel(nodeScriptViewModel.NodeScript);
|
CustomNodeViewModel = coreNode.GetCustomViewModel(nodeScriptViewModel.NodeScript);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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<Enum, InputPin> _inputPins;
|
||||||
|
|
||||||
|
public EnumSwitchNode() : base("Enum Branch", "desc")
|
||||||
|
{
|
||||||
|
_inputPins = new Dictionary<Enum, InputPin>();
|
||||||
|
|
||||||
|
Output = CreateOutputPin(typeof(object), "Result");
|
||||||
|
SwitchValue = CreateInputPin<Enum>("Switch");
|
||||||
|
|
||||||
|
SwitchValue.PinConnected += OnSwitchPinConnected;
|
||||||
|
SwitchValue.PinDisconnected += OnSwitchPinDisconnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OutputPin Output { get; }
|
||||||
|
public InputPin<Enum> 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<IPin> 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<IPin> 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<IPin> e)
|
||||||
|
{
|
||||||
|
if (SwitchValue.ConnectedTo.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Type enumType = SwitchValue.ConnectedTo[0].Type;
|
||||||
|
foreach (Enum enumValue in Enum.GetValues(enumType).Cast<Enum>())
|
||||||
|
{
|
||||||
|
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<IPin> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user