diff --git a/src/Artemis.Core/Extensions/TypeExtensions.cs b/src/Artemis.Core/Extensions/TypeExtensions.cs index 44f851c16..672c76e15 100644 --- a/src/Artemis.Core/Extensions/TypeExtensions.cs +++ b/src/Artemis.Core/Extensions/TypeExtensions.cs @@ -130,8 +130,11 @@ namespace Artemis.Core /// at all /// /// - public static int ScoreCastability(this Type to, Type from) + public static int ScoreCastability(this Type to, Type? from) { + if (from == null) + return 0; + if (to == from) return 5; if (to.TypeIsNumber() && from.TypeIsNumber()) diff --git a/src/Artemis.Core/VisualScripting/InputPinCollection.cs b/src/Artemis.Core/VisualScripting/InputPinCollection.cs index 93a474e19..33042cfbe 100644 --- a/src/Artemis.Core/VisualScripting/InputPinCollection.cs +++ b/src/Artemis.Core/VisualScripting/InputPinCollection.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; @@ -31,4 +32,38 @@ namespace Artemis.Core #endregion } + + public sealed class InputPinCollection : PinCollection + { + #region Properties & Fields + + public override PinDirection Direction => PinDirection.Input; + public override Type Type { get; } + + public new IEnumerable Pins => base.Pins.Cast(); + + public IEnumerable Values => Pins.Select(p => p.Value); + + #endregion + + #region Constructors + + internal InputPinCollection(INode node, Type type, string name, int initialCount) + : base(node, name, 0) + { + this.Type = type; + + // Can't do this in the base constructor because the type won't be set yet + for (int i = 0; i < initialCount; i++) + AddPin(); + } + + #endregion + + #region Methods + + protected override IPin CreatePin() => new InputPin(Node, Type, string.Empty); + + #endregion + } } diff --git a/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs b/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs index 4328e440b..b4627f977 100644 --- a/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs +++ b/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs @@ -22,5 +22,6 @@ namespace Artemis.Core void ConnectTo(IPin pin); void DisconnectFrom(IPin pin); + void DisconnectAll(); } } diff --git a/src/Artemis.Core/VisualScripting/Node.cs b/src/Artemis.Core/VisualScripting/Node.cs index 669de437f..dfb232fc8 100644 --- a/src/Artemis.Core/VisualScripting/Node.cs +++ b/src/Artemis.Core/VisualScripting/Node.cs @@ -130,6 +130,14 @@ namespace Artemis.Core return pin; } + protected InputPinCollection CreateInputPinCollection(Type type, string name = "", int initialCount = 1) + { + InputPinCollection pin = new(this, type, name, initialCount); + _pinCollections.Add(pin); + OnPropertyChanged(nameof(PinCollections)); + return pin; + } + protected OutputPinCollection CreateOutputPinCollection(string name = "", int initialCount = 1) { OutputPinCollection pin = new(this, name, initialCount); @@ -138,6 +146,19 @@ namespace Artemis.Core return pin; } + protected bool RemovePinCollection(PinCollection pinCollection) + { + bool isRemoved = _pinCollections.Remove(pinCollection); + if (isRemoved) + { + foreach (IPin pin in pinCollection) + pin.DisconnectAll(); + OnPropertyChanged(nameof(PinCollections)); + } + + return isRemoved; + } + public virtual void Initialize(INodeScript script) { } diff --git a/src/Artemis.VisualScripting/Editor/Controls/VisualScriptCablePresenter.cs b/src/Artemis.VisualScripting/Editor/Controls/VisualScriptCablePresenter.cs index f20059d09..85b954b7d 100644 --- a/src/Artemis.VisualScripting/Editor/Controls/VisualScriptCablePresenter.cs +++ b/src/Artemis.VisualScripting/Editor/Controls/VisualScriptCablePresenter.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.ComponentModel; using System.Linq; using System.Windows; @@ -7,7 +6,6 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using System.Windows.Shapes; -using Artemis.Core; using Artemis.UI.Shared; using Artemis.VisualScripting.Editor.Controls.Wrapper; @@ -75,7 +73,7 @@ namespace Artemis.VisualScripting.Editor.Controls { _path = GetTemplateChild(PART_PATH) as Path ?? throw new NullReferenceException($"The Path '{PART_PATH}' is missing."); _valueBorder = GetTemplateChild("PART_ValueDisplay") as Border ?? throw new NullReferenceException("The Border 'PART_ValueDisplay' is missing."); - + _path.MouseEnter += (_, _) => UpdateValueVisibility(); _path.MouseLeave += (_, _) => UpdateValueVisibility(); _valueBorder.MouseEnter += (_, _) => UpdateValueVisibility(); @@ -95,13 +93,15 @@ namespace Artemis.VisualScripting.Editor.Controls private void OnPathMouseDown(object sender, MouseButtonEventArgs args) { - if ((args.ChangedButton == MouseButton.Left) && (args.LeftButton == MouseButtonState.Pressed) && (args.ClickCount == 2)) + if (args.ChangedButton == MouseButton.Left && args.LeftButton == MouseButtonState.Pressed && args.ClickCount == 2) { //TODO DarthAffe 17.06.2021: Should we add rerouting? //AddRerouteNode(); } else if (args.ChangedButton == MouseButton.Middle) + { Cable.Disconnect(); + } } private static void CableChanged(DependencyObject d, DependencyPropertyChangedEventArgs args) @@ -167,8 +167,8 @@ namespace Artemis.VisualScripting.Editor.Controls return; ValuePosition = new Point( - Cable.From.AbsolutePosition.X + ((Cable.To.AbsolutePosition.X - Cable.From.AbsolutePosition.X) / 2), - Cable.From.AbsolutePosition.Y + ((Cable.To.AbsolutePosition.Y - Cable.From.AbsolutePosition.Y) / 2) + Cable.From.AbsolutePosition.X + (Cable.To.AbsolutePosition.X - Cable.From.AbsolutePosition.X) / 2, + Cable.From.AbsolutePosition.Y + (Cable.To.AbsolutePosition.Y - Cable.From.AbsolutePosition.Y) / 2 ); } diff --git a/src/Artemis.VisualScripting/Editor/Styles/VisualScriptCablePresenter.xaml b/src/Artemis.VisualScripting/Editor/Styles/VisualScriptCablePresenter.xaml index 57770438c..9419837ba 100644 --- a/src/Artemis.VisualScripting/Editor/Styles/VisualScriptCablePresenter.xaml +++ b/src/Artemis.VisualScripting/Editor/Styles/VisualScriptCablePresenter.xaml @@ -7,6 +7,7 @@ xmlns:skiaSharp="clr-namespace:SkiaSharp;assembly=SkiaSharp" xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"> + @@ -74,14 +75,16 @@ - - - - - - + + + + + diff --git a/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelEventNodeCustomViewModel.cs b/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelEventNodeCustomViewModel.cs index 0057dcbea..d68945c8b 100644 --- a/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelEventNodeCustomViewModel.cs +++ b/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelEventNodeCustomViewModel.cs @@ -3,9 +3,10 @@ using System.ComponentModel; using Artemis.Core; using Artemis.Core.Modules; using Artemis.Core.Services; +using Artemis.VisualScripting.Nodes.CustomViewModels; using Stylet; -namespace Artemis.VisualScripting.Nodes.CustomViewModels +namespace Artemis.VisualScripting.Nodes.DataModel.CustomViewModels { public class DataModelEventNodeCustomViewModel : CustomNodeViewModel { @@ -22,7 +23,7 @@ namespace Artemis.VisualScripting.Nodes.CustomViewModels public PluginSetting ShowFullPaths { get; } public PluginSetting ShowDataModelValues { get; } - public BindableCollection FilterTypes { get; } = new() { typeof(DataModelEvent) }; + public BindableCollection FilterTypes { get; } = new() { typeof(IDataModelEvent) }; public BindableCollection Modules { diff --git a/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelNodeCustomViewModel.cs b/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelNodeCustomViewModel.cs index 44db086bd..0eca3ad42 100644 --- a/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelNodeCustomViewModel.cs +++ b/src/Artemis.VisualScripting/Nodes/DataModel/CustomViewModels/DataModelNodeCustomViewModel.cs @@ -2,9 +2,10 @@ using Artemis.Core; using Artemis.Core.Modules; using Artemis.Core.Services; +using Artemis.VisualScripting.Nodes.CustomViewModels; using Stylet; -namespace Artemis.VisualScripting.Nodes.CustomViewModels +namespace Artemis.VisualScripting.Nodes.DataModel.CustomViewModels { public class DataModelNodeCustomViewModel : CustomNodeViewModel { diff --git a/src/Artemis.VisualScripting/Nodes/DataModel/CustomViews/DataModelEventNodeCustomView.xaml b/src/Artemis.VisualScripting/Nodes/DataModel/CustomViews/DataModelEventNodeCustomView.xaml index 52708c600..9760bbaba 100644 --- a/src/Artemis.VisualScripting/Nodes/DataModel/CustomViews/DataModelEventNodeCustomView.xaml +++ b/src/Artemis.VisualScripting/Nodes/DataModel/CustomViews/DataModelEventNodeCustomView.xaml @@ -1,4 +1,4 @@ - - + ButtonBrush="DarkGoldenrod"/> diff --git a/src/Artemis.VisualScripting/Nodes/DataModel/CustomViews/DataModelNodeCustomView.xaml b/src/Artemis.VisualScripting/Nodes/DataModel/CustomViews/DataModelNodeCustomView.xaml index c5ff39d78..749c09cbb 100644 --- a/src/Artemis.VisualScripting/Nodes/DataModel/CustomViews/DataModelNodeCustomView.xaml +++ b/src/Artemis.VisualScripting/Nodes/DataModel/CustomViews/DataModelNodeCustomView.xaml @@ -1,4 +1,4 @@ -, IDisposable + { + private DataModelPath _dataModelPath; + private DateTime _lastTrigger; + private int _currentIndex; + + public DataModelEventNode() : base("Data Model-Event", "Responds to a data model event trigger") + { + Input = CreateInputPin(); + Input.PinConnected += InputOnPinConnected; + } + + public InputPin Input { get; } + + public InputPinCollection CycleValues { get; set; } + public OutputPin Output { get; set; } + public INodeScript Script { get; set; } + + public DataModelPath DataModelPath + { + get => _dataModelPath; + set => SetAndNotify(ref _dataModelPath, value); + } + + public override void Initialize(INodeScript script) + { + Script = script; + CreateCycleValues(); + CreateOutput(); + + if (Storage is not DataModelPathEntity pathEntity) + return; + + DataModelPath = new DataModelPath(pathEntity); + } + + public override void Evaluate() + { + object outputValue = null; + if (DataModelPath?.GetValue() is DataModelEvent dataModelEvent) + { + if (dataModelEvent.LastTrigger > _lastTrigger) + { + _lastTrigger = dataModelEvent.LastTrigger; + _currentIndex++; + + if (_currentIndex > CycleValues.Count()) + _currentIndex = 0; + } + + outputValue = _currentIndex == 0 + ? Input.Value + : CycleValues.ElementAt(_currentIndex - 1).PinValue; + } + + Output.Value = outputValue ?? Output.Type.GetDefault(); + } + + private void InputOnPinConnected(object sender, SingleValueEventArgs e) + { + CreateCycleValues(); + CreateOutput(); + } + + private void CreateCycleValues() + { + int pinCount = CycleValues?.Count() ?? 1; + Type inputType = Input.ConnectedTo.FirstOrDefault()?.Type ?? typeof(object); + + if (CycleValues != null) + { + if (inputType == CycleValues.Type) + return; + RemovePinCollection(CycleValues); + } + + CycleValues = CreateInputPinCollection(inputType, "", pinCount); + } + + private void CreateOutput() + { + Type inputType = Input.ConnectedTo.FirstOrDefault()?.Type ?? typeof(object); + + if (Output != null) + { + if (inputType == Output.Type) + return; + RemovePin(Output); + } + + Output = CreateOutputPin(inputType); + } + + /// + public void Dispose() + { + } + } +} \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/DataModelNode.cs b/src/Artemis.VisualScripting/Nodes/DataModel/DataModelNode.cs similarity index 95% rename from src/Artemis.VisualScripting/Nodes/DataModelNode.cs rename to src/Artemis.VisualScripting/Nodes/DataModel/DataModelNode.cs index 44869c711..056a6ae92 100644 --- a/src/Artemis.VisualScripting/Nodes/DataModelNode.cs +++ b/src/Artemis.VisualScripting/Nodes/DataModel/DataModelNode.cs @@ -1,11 +1,10 @@ using System; -using System.Linq; using Artemis.Core; using Artemis.Storage.Entities.Profile; -using Artemis.VisualScripting.Nodes.CustomViewModels; +using Artemis.VisualScripting.Nodes.DataModel.CustomViewModels; using Stylet; -namespace Artemis.VisualScripting.Nodes +namespace Artemis.VisualScripting.Nodes.DataModel { [Node("Data Model-Value", "Outputs a selectable data model value.", "External")] public class DataModelNode : Node, IDisposable diff --git a/src/Artemis.VisualScripting/Nodes/DataModelEventNode.cs b/src/Artemis.VisualScripting/Nodes/DataModelEventNode.cs deleted file mode 100644 index 89e6afe8a..000000000 --- a/src/Artemis.VisualScripting/Nodes/DataModelEventNode.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using Artemis.Core; -using Artemis.Storage.Entities.Profile; -using Artemis.VisualScripting.Nodes.CustomViewModels; - -namespace Artemis.VisualScripting.Nodes -{ - [Node("Data Model-Event", "Responds to a data model event trigger", "External", OutputType = typeof(bool))] - public class DataModelEventNode : Node, IDisposable - { - private DataModelPath _dataModelPath; - - public DataModelEventNode() : base("Data Model-Event", "Responds to a data model event trigger") - { - Output = CreateOutputPin(); - } - - public OutputPin Output { get; } - public INodeScript Script { get; set; } - - public DataModelPath DataModelPath - { - get => _dataModelPath; - set => SetAndNotify(ref _dataModelPath, value); - } - - public override void Initialize(INodeScript script) - { - Script = script; - - if (Storage is not DataModelPathEntity pathEntity) - return; - - DataModelPath = new DataModelPath(pathEntity); - DataModelPath.PathValidated += DataModelPathOnPathValidated; - } - - public override void Evaluate() - { - } - - private void DataModelPathOnPathValidated(object sender, EventArgs e) - { - } - - /// - public void Dispose() - { - } - } -} \ No newline at end of file