1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Nodes - Added node type registration system

Nodes - Moved models and node logic into core
Nodes - Added node service that leverages DI
This commit is contained in:
Robert 2021-08-07 21:05:15 +02:00
parent 51541b4e6e
commit 7eadc58bee
57 changed files with 481 additions and 259 deletions

View File

@ -1,5 +1,6 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=defaulttypes/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=defaulttypes/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cnodes/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofileconfiguration/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofileconfiguration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cadaption/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cadaption/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cadaptionhints/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cadaptionhints/@EntryIndexedValue">True</s:Boolean>
@ -49,6 +50,8 @@
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Clayershapes/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Clayershapes/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Csurface/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Csurface/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Csurface_005Clayout/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Csurface_005Clayout/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cvisualscripting/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cvisualscripting_005Cinterfaces/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=mvvm/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=mvvm/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=placeholders/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=placeholders/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=plugins/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=plugins/@EntryIndexedValue">True</s:Boolean>
@ -83,4 +86,6 @@
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cwebserver_005Cjson/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cwebserver_005Cjson/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=stores/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=stores/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=stores_005Cregistrations/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=stores_005Cregistrations/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=utilities/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=utilities/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=visualscripting/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=visualscripting_005Cinterfaces/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -0,0 +1,12 @@
namespace Artemis.Core
{
internal class NodeTypeStoreEvent
{
public NodeTypeStoreEvent(NodeTypeRegistration typeRegistration)
{
TypeRegistration = typeRegistration;
}
public NodeTypeRegistration TypeRegistration { get; }
}
}

View File

@ -66,9 +66,9 @@ namespace Artemis.Core
internal void LoadRenderElement() internal void LoadRenderElement()
{ {
DisplayCondition = RenderElementEntity.DisplayCondition != null // DisplayCondition = RenderElementEntity.DisplayCondition != null
? new DataModelConditionGroup(null, RenderElementEntity.DisplayCondition) // ? new DataModelConditionGroup(null, RenderElementEntity.DisplayCondition)
: new DataModelConditionGroup(null); // : new DataModelConditionGroup(null);
Timeline = RenderElementEntity.Timeline != null Timeline = RenderElementEntity.Timeline != null
? new Timeline(RenderElementEntity.Timeline) ? new Timeline(RenderElementEntity.Timeline)
@ -97,8 +97,8 @@ namespace Artemis.Core
} }
// Conditions // Conditions
RenderElementEntity.DisplayCondition = DisplayCondition?.Entity; // RenderElementEntity.DisplayCondition = DisplayCondition?.Entity;
DisplayCondition?.Save(); // DisplayCondition?.Save();
// Timeline // Timeline
RenderElementEntity.Timeline = Timeline?.Entity; RenderElementEntity.Timeline = Timeline?.Entity;
@ -125,8 +125,8 @@ namespace Artemis.Core
{ {
// The play mode dictates whether to stick to the main segment unless the display conditions contains events // The play mode dictates whether to stick to the main segment unless the display conditions contains events
bool stickToMainSegment = (Timeline.PlayMode == TimelinePlayMode.Repeat || Timeline.EventOverlapMode == TimeLineEventOverlapMode.Toggle) && DisplayConditionMet; bool stickToMainSegment = (Timeline.PlayMode == TimelinePlayMode.Repeat || Timeline.EventOverlapMode == TimeLineEventOverlapMode.Toggle) && DisplayConditionMet;
if (DisplayCondition != null && DisplayCondition.ContainsEvents && Timeline.EventOverlapMode != TimeLineEventOverlapMode.Toggle) // if (DisplayCondition != null && DisplayCondition.ContainsEvents && Timeline.EventOverlapMode != TimeLineEventOverlapMode.Toggle)
stickToMainSegment = false; // stickToMainSegment = false;
Timeline.Update(TimeSpan.FromSeconds(deltaTime), stickToMainSegment); Timeline.Update(TimeSpan.FromSeconds(deltaTime), stickToMainSegment);
} }
@ -354,14 +354,14 @@ namespace Artemis.Core
protected set => SetAndNotify(ref _displayConditionMet, value); protected set => SetAndNotify(ref _displayConditionMet, value);
} }
private DataModelConditionGroup? _displayCondition; private NodeScript<bool>? _displayCondition;
private bool _displayConditionMet; private bool _displayConditionMet;
private bool _toggledOnByEvent = false; private bool _toggledOnByEvent = false;
/// <summary> /// <summary>
/// Gets or sets the root display condition group /// Gets or sets the root display condition group
/// </summary> /// </summary>
public DataModelConditionGroup? DisplayCondition public NodeScript<bool>? DisplayCondition
{ {
get => _displayCondition; get => _displayCondition;
set => SetAndNotify(ref _displayCondition, value); set => SetAndNotify(ref _displayCondition, value);
@ -387,20 +387,22 @@ namespace Artemis.Core
if (Timeline.EventOverlapMode != TimeLineEventOverlapMode.Toggle) if (Timeline.EventOverlapMode != TimeLineEventOverlapMode.Toggle)
_toggledOnByEvent = false; _toggledOnByEvent = false;
bool conditionMet = DisplayCondition.Evaluate(); DisplayCondition.Run();
bool conditionMet = DisplayCondition.Result;
if (Parent is RenderProfileElement parent && !parent.DisplayConditionMet) if (Parent is RenderProfileElement parent && !parent.DisplayConditionMet)
conditionMet = false; conditionMet = false;
if (!DisplayCondition.ContainsEvents) // if (!DisplayCondition.ContainsEvents)
{ // {
// Regular conditions reset the timeline whenever their condition is met and was not met before that // // Regular conditions reset the timeline whenever their condition is met and was not met before that
if (conditionMet && !DisplayConditionMet && Timeline.IsFinished) // if (conditionMet && !DisplayConditionMet && Timeline.IsFinished)
Timeline.JumpToStart(); // Timeline.JumpToStart();
// If regular conditions are no longer met, jump to the end segment if stop mode requires it // // If regular conditions are no longer met, jump to the end segment if stop mode requires it
if (!conditionMet && Timeline.StopMode == TimelineStopMode.SkipToEnd) // if (!conditionMet && Timeline.StopMode == TimelineStopMode.SkipToEnd)
Timeline.JumpToEndSegment(); // Timeline.JumpToEndSegment();
} // }
else if (conditionMet) // else if (conditionMet)
if (conditionMet)
{ {
if (Timeline.EventOverlapMode == TimeLineEventOverlapMode.Toggle) if (Timeline.EventOverlapMode == TimeLineEventOverlapMode.Toggle)
{ {

View File

@ -107,7 +107,7 @@ namespace Artemis.Core
GetRegionData(skRectI.Left, skRectI.Top, skRectI.Width, skRectI.Height, buffer); GetRegionData(skRectI.Left, skRectI.Top, skRectI.Width, skRectI.Height, buffer);
Span<byte> pixelData = stackalloc byte[DATA_PER_PIXEL]; Span<byte> pixelData = stackalloc byte[DATA_PER_PIXEL];
Sampler.SampleColor(new SamplerInfo<byte>(skRectI.Width, skRectI.Height, buffer), pixelData); Sampler.Sample(new SamplerInfo<byte>(skRectI.Width, skRectI.Height, buffer), pixelData);
return GetColor(pixelData); return GetColor(pixelData);
} }
@ -119,7 +119,7 @@ namespace Artemis.Core
GetRegionData(skRectI.Left, skRectI.Top, skRectI.Width, skRectI.Height, buffer); GetRegionData(skRectI.Left, skRectI.Top, skRectI.Width, skRectI.Height, buffer);
Span<byte> pixelData = stackalloc byte[DATA_PER_PIXEL]; Span<byte> pixelData = stackalloc byte[DATA_PER_PIXEL];
Sampler.SampleColor(new SamplerInfo<byte>(skRectI.Width, skRectI.Height, buffer), pixelData); Sampler.Sample(new SamplerInfo<byte>(skRectI.Width, skRectI.Height, buffer), pixelData);
ArrayPool<byte>.Shared.Return(rent); ArrayPool<byte>.Shared.Return(rent);

View File

@ -4,7 +4,7 @@ using Artemis.Core.ScriptingProviders;
namespace Artemis.Core.Services namespace Artemis.Core.Services
{ {
/// <summary> /// <summary>
/// A service that allows you to manage various types of <see cref="Script" /> instances /// A service that allows you to manage various types of <see cref="NodeScript" /> instances
/// </summary> /// </summary>
public interface IScriptingService : IArtemisService public interface IScriptingService : IArtemisService
{ {

View File

@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Ninject;
namespace Artemis.Core.Services
{
internal class NodeService : INodeService
{
private readonly IKernel _kernel;
#region Constants
private static readonly Type TYPE_NODE = typeof(INode);
#endregion
#region Properties & Fields
public IEnumerable<NodeData> AvailableNodes => NodeTypeStore.GetAll();
#endregion
#region Constructors
public NodeService(IKernel kernel)
{
_kernel = kernel;
}
#endregion
#region Methods
public NodeTypeRegistration RegisterNodeType(Plugin plugin, Type nodeType)
{
if (plugin == null) throw new ArgumentNullException(nameof(plugin));
if (nodeType == null) throw new ArgumentNullException(nameof(nodeType));
if (!TYPE_NODE.IsAssignableFrom(nodeType)) throw new ArgumentException("Node has to be a base type of the Node-Type.", nameof(nodeType));
NodeAttribute? nodeAttribute = nodeType.GetCustomAttribute<NodeAttribute>();
string name = nodeAttribute?.Name ?? nodeType.Name;
string description = nodeAttribute?.Description ?? string.Empty;
string category = nodeAttribute?.Category ?? string.Empty;
NodeData nodeData = new(plugin, nodeType, name, description, category, () => CreateNode(nodeType));
return NodeTypeStore.Add(nodeData);
}
private INode CreateNode(Type nodeType)
{
INode node = _kernel.Get(nodeType) as INode ?? throw new InvalidOperationException($"Node {nodeType} is not an INode");
if (node.CustomViewModelType != null)
node.CustomViewModel = _kernel.Get(node.CustomViewModelType);
return node;
}
#endregion
}
/// <summary>
/// A service that provides access to the node system
/// </summary>
public interface INodeService : IArtemisService
{
/// <summary>
/// Gets all available nodes
/// </summary>
IEnumerable<NodeData> AvailableNodes { get; }
/// <summary>
/// Initializes a node of the provided <paramref name="nodeType"/>
/// </summary>
/// <param name="plugin">The plugin the node belongs to</param>
/// <param name="nodeType">The type of node to initialize</param>
NodeTypeRegistration RegisterNodeType(Plugin plugin, Type nodeType);
}
}

View File

@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Artemis.Core
{
internal class NodeTypeStore
{
private static readonly List<NodeTypeRegistration> Registrations = new();
public static NodeTypeRegistration Add(NodeData nodeData)
{
if (nodeData.Plugin == null)
throw new ArtemisCoreException("Cannot add a data binding modifier type that is not associated with a plugin");
NodeTypeRegistration typeRegistration;
lock (Registrations)
{
if (Registrations.Any(r => r.NodeData == nodeData))
throw new ArtemisCoreException($"Data binding modifier type store already contains modifier '{nodeData.Name}'");
typeRegistration = new NodeTypeRegistration(nodeData, nodeData.Plugin) { IsInStore = true };
Registrations.Add(typeRegistration);
}
OnDataBindingModifierAdded(new NodeTypeStoreEvent(typeRegistration));
return typeRegistration;
}
public static void Remove(NodeTypeRegistration typeRegistration)
{
lock (Registrations)
{
if (!Registrations.Contains(typeRegistration))
throw new ArtemisCoreException($"Data binding modifier type store does not contain modifier type '{typeRegistration.NodeData.Name}'");
Registrations.Remove(typeRegistration);
typeRegistration.IsInStore = false;
}
OnDataBindingModifierRemoved(new NodeTypeStoreEvent(typeRegistration));
}
public static IEnumerable<NodeData> GetAll()
{
lock (Registrations)
{
return Registrations.Select(r => r.NodeData).ToList();
}
}
public static NodeTypeRegistration? Get(Guid pluginGuid, string type)
{
lock (Registrations)
{
return Registrations.FirstOrDefault(r => r.Plugin.Guid == pluginGuid && r.NodeData.Type.Name == type);
}
}
#region Events
public static event EventHandler<NodeTypeStoreEvent>? DataBindingModifierAdded;
public static event EventHandler<NodeTypeStoreEvent>? DataBindingModifierRemoved;
private static void OnDataBindingModifierAdded(NodeTypeStoreEvent e)
{
DataBindingModifierAdded?.Invoke(null, e);
}
private static void OnDataBindingModifierRemoved(NodeTypeStoreEvent e)
{
DataBindingModifierRemoved?.Invoke(null, e);
}
#endregion
}
}

View File

@ -0,0 +1,37 @@
using System;
namespace Artemis.Core
{
/// <summary>
/// Represents a registration for a type of <see cref="INode"/>
/// </summary>
public class NodeTypeRegistration
{
internal NodeTypeRegistration(NodeData nodeData, Plugin plugin)
{
NodeData = nodeData;
Plugin = plugin;
Plugin.Disabled += OnDisabled;
}
public NodeData NodeData { get; }
/// <summary>
/// Gets the plugin the node is associated with
/// </summary>
public Plugin Plugin { get; }
/// <summary>
/// Gets a boolean indicating whether the registration is in the internal Core store
/// </summary>
public bool IsInStore { get; internal set; }
private void OnDisabled(object? sender, EventArgs e)
{
Plugin.Disabled -= OnDisabled;
if (IsInStore)
NodeTypeStore.Remove(this);
}
}
}

View File

@ -1,7 +1,6 @@
using System; using System;
using Artemis.Core.VisualScripting;
namespace Artemis.VisualScripting.Model namespace Artemis.Core
{ {
public sealed class InputPin<T> : Pin public sealed class InputPin<T> : Pin
{ {

View File

@ -1,9 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Artemis.Core.VisualScripting;
namespace Artemis.VisualScripting.Model namespace Artemis.Core
{ {
public sealed class InputPinCollection<T> : PinCollection public sealed class InputPinCollection<T> : PinCollection
{ {

View File

@ -2,12 +2,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
namespace Artemis.Core.VisualScripting namespace Artemis.Core
{ {
public interface INode : INotifyPropertyChanged public interface INode : INotifyPropertyChanged
{ {
string Name { get; } string Name { get; }
string Description { get; } string Description { get; }
bool IsExitNode { get; }
public double X { get; set; } public double X { get; set; }
public double Y { get; set; } public double Y { get; set; }
@ -15,8 +16,8 @@ namespace Artemis.Core.VisualScripting
public IReadOnlyCollection<IPin> Pins { get; } public IReadOnlyCollection<IPin> Pins { get; }
public IReadOnlyCollection<IPinCollection> PinCollections { get; } public IReadOnlyCollection<IPinCollection> PinCollections { get; }
public object CustomView { get; } public Type? CustomViewModelType { get; }
public object CustomViewModel { get; } public object? CustomViewModel { get; set; }
event EventHandler Resetting; event EventHandler Resetting;

View File

@ -2,9 +2,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
namespace Artemis.Core.VisualScripting namespace Artemis.Core
{ {
public interface IScript : INotifyPropertyChanged, IDisposable public interface INodeScript : INotifyPropertyChanged, IDisposable
{ {
string Name { get; } string Name { get; }
string Description { get; } string Description { get; }
@ -18,7 +18,7 @@ namespace Artemis.Core.VisualScripting
void RemoveNode(INode node); void RemoveNode(INode node);
} }
public interface IScript<out T> : IScript public interface INodeScript<out T> : INodeScript
{ {
T Result { get; } T Result { get; }
} }

View File

@ -1,8 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Artemis.VisualScripting.Model;
namespace Artemis.Core.VisualScripting namespace Artemis.Core
{ {
public interface IPin public interface IPin
{ {

View File

@ -1,8 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Artemis.VisualScripting.Model;
namespace Artemis.Core.VisualScripting namespace Artemis.Core
{ {
public interface IPinCollection : IEnumerable<IPin> public interface IPinCollection : IEnumerable<IPin>
{ {

View File

@ -1,7 +1,4 @@
using Artemis.Core.VisualScripting; namespace Artemis.Core.Internal
using Artemis.VisualScripting.Model;
namespace Artemis.VisualScripting.Internal
{ {
internal interface IExitNode : INode internal interface IExitNode : INode
{ } { }
@ -14,6 +11,8 @@ namespace Artemis.VisualScripting.Internal
public T Value { get; private set; } public T Value { get; private set; }
public override bool IsExitNode => true;
#endregion #endregion
#region Constructors #region Constructors

View File

@ -1,52 +1,55 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Windows;
using Artemis.Core.VisualScripting;
using Artemis.VisualScripting.ViewModel;
namespace Artemis.VisualScripting.Model namespace Artemis.Core
{ {
public abstract class Node : AbstractBindable, INode public abstract class Node : CorePropertyChanged, INode
{ {
#region Properties & Fields #region Properties & Fields
private string _name; private string _name;
public string Name public string Name
{ {
get => _name; get => _name;
protected set => SetProperty(ref _name, value); protected set => SetAndNotify(ref _name, value);
} }
private string _description; private string _description;
public string Description public string Description
{ {
get => _description; get => _description;
protected set => SetProperty(ref _description, value); protected set => SetAndNotify(ref _description, value);
} }
private double _x; private double _x;
public double X public double X
{ {
get => _x; get => _x;
set => SetProperty(ref _x, value); set => SetAndNotify(ref _x, value);
} }
private double _y; private double _y;
public double Y public double Y
{ {
get => _y; get => _y;
set => SetProperty(ref _y, value); set => SetAndNotify(ref _y, value);
} }
public virtual bool IsExitNode => false;
private readonly List<IPin> _pins = new(); private readonly List<IPin> _pins = new();
public IReadOnlyCollection<IPin> Pins => new ReadOnlyCollection<IPin>(_pins); public IReadOnlyCollection<IPin> Pins => new ReadOnlyCollection<IPin>(_pins);
private readonly List<IPinCollection> _pinCollections = new(); private readonly List<IPinCollection> _pinCollections = new();
public IReadOnlyCollection<IPinCollection> PinCollections => new ReadOnlyCollection<IPinCollection>(_pinCollections); public IReadOnlyCollection<IPinCollection> PinCollections => new ReadOnlyCollection<IPinCollection>(_pinCollections);
public object CustomView { get; private set; } public Type? CustomViewModelType { get; private set; }
public object CustomViewModel { get; private set; } public object? CustomViewModel { get; set; }
#endregion #endregion
@ -59,7 +62,8 @@ namespace Artemis.VisualScripting.Model
#region Construtors #region Construtors
protected Node() protected Node()
{ } {
}
protected Node(string name, string description) protected Node(string name, string description)
{ {
@ -111,6 +115,7 @@ namespace Artemis.VisualScripting.Model
pin.DisconnectAll(); pin.DisconnectAll();
OnPropertyChanged(nameof(Pins)); OnPropertyChanged(nameof(Pins));
} }
return isRemoved; return isRemoved;
} }
@ -130,10 +135,9 @@ namespace Artemis.VisualScripting.Model
return pin; return pin;
} }
protected void RegisterCustomView(DataTemplate view, object viewModel) protected void RegisterCustomViewModel<T>()
{ {
CustomView = view; CustomViewModelType = typeof(T);
CustomViewModel = viewModel;
} }
public abstract void Evaluate(); public abstract void Evaluate();
@ -145,4 +149,4 @@ namespace Artemis.VisualScripting.Model
#endregion #endregion
} }
} }

View File

@ -1,8 +1,8 @@
using System; using System;
namespace Artemis.VisualScripting.Attributes namespace Artemis.Core
{ {
public class UIAttribute : Attribute public class NodeAttribute : Attribute
{ {
#region Properties & Fields #region Properties & Fields
@ -14,18 +14,18 @@ namespace Artemis.VisualScripting.Attributes
#region Constructors #region Constructors
public UIAttribute(string name) public NodeAttribute(string name)
{ {
this.Name = name; this.Name = name;
} }
public UIAttribute(string name, string description) public NodeAttribute(string name, string description)
{ {
this.Name = name; this.Name = name;
this.Description = description; this.Description = description;
} }
public UIAttribute(string name, string description, string category) public NodeAttribute(string name, string description, string category)
{ {
this.Name = name; this.Name = name;
this.Description = description; this.Description = description;

View File

@ -1,25 +1,27 @@
using System; using System;
using Artemis.Core.VisualScripting;
namespace Artemis.VisualScripting.Model namespace Artemis.Core
{ {
public class NodeData public class NodeData
{ {
#region Properties & Fields #region Properties & Fields
public Plugin Plugin { get; }
public Type Type { get; } public Type Type { get; }
public string Name { get; } public string Name { get; }
public string Description { get; } public string Description { get; }
public string Category { get; } public string Category { get; }
private Func<INode> _create; private Func<INode> _create;
#endregion #endregion
#region Constructors #region Constructors
public NodeData(Type type, string name, string description, string category, Func<INode> create) internal NodeData(Plugin plugin, Type type, string name, string description, string category, Func<INode> create)
{ {
this.Plugin = plugin;
this.Type = type; this.Type = type;
this.Name = name; this.Name = name;
this.Description = description; this.Description = description;

View File

@ -1,14 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using Artemis.Core.VisualScripting; using Artemis.Core.Internal;
using Artemis.VisualScripting.Internal; using Artemis.Core.Properties;
using Artemis.VisualScripting.ViewModel;
using JetBrains.Annotations;
namespace Artemis.VisualScripting.Model namespace Artemis.Core
{ {
public abstract class Script : AbstractBindable, IScript public abstract class NodeScript : CorePropertyChanged, INodeScript
{ {
#region Properties & Fields #region Properties & Fields
@ -25,7 +23,7 @@ namespace Artemis.VisualScripting.Model
#region Constructors #region Constructors
public Script(string name, string description) public NodeScript(string name, string description)
{ {
this.Name = name; this.Name = name;
this.Description = description; this.Description = description;
@ -59,7 +57,7 @@ namespace Artemis.VisualScripting.Model
#endregion #endregion
} }
public class Script<T> : Script, IScript<T> public class NodeScript<T> : NodeScript, INodeScript<T>
{ {
#region Properties & Fields #region Properties & Fields
@ -71,7 +69,7 @@ namespace Artemis.VisualScripting.Model
#region Constructors #region Constructors
public Script(string name, string description) public NodeScript(string name, string description)
: base(name, description) : base(name, description)
{ {
ExitNode = new ExitNode<T>(name, description); ExitNode = new ExitNode<T>(name, description);
@ -79,7 +77,7 @@ namespace Artemis.VisualScripting.Model
} }
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedWithFixedConstructorSignature)] [UsedImplicitly(ImplicitUseKindFlags.InstantiatedWithFixedConstructorSignature)]
private Script(string name, string description, INode exitNode) private NodeScript(string name, string description, INode exitNode)
: base(name, description) : base(name, description)
{ {
ExitNode = exitNode; ExitNode = exitNode;

View File

@ -1,7 +1,6 @@
using System; using System;
using Artemis.Core.VisualScripting;
namespace Artemis.VisualScripting.Model namespace Artemis.Core
{ {
public sealed class OutputPin<T> : Pin public sealed class OutputPin<T> : Pin
{ {

View File

@ -1,7 +1,6 @@
using System; using System;
using Artemis.Core.VisualScripting;
namespace Artemis.VisualScripting.Model namespace Artemis.Core
{ {
public sealed class OutputPinCollection<T> : PinCollection public sealed class OutputPinCollection<T> : PinCollection
{ {

View File

@ -1,12 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using Artemis.Core.VisualScripting;
using Artemis.VisualScripting.ViewModel;
namespace Artemis.VisualScripting.Model namespace Artemis.Core
{ {
public abstract class Pin : AbstractBindable, IPin public abstract class Pin : CorePropertyChanged, IPin
{ {
#region Properties & Fields #region Properties & Fields
@ -17,7 +15,7 @@ namespace Artemis.VisualScripting.Model
public bool IsEvaluated public bool IsEvaluated
{ {
get => _isEvaluated; get => _isEvaluated;
set => SetProperty(ref _isEvaluated, value); set => SetAndNotify(ref _isEvaluated, value);
} }
private readonly List<IPin> _connectedTo = new(); private readonly List<IPin> _connectedTo = new();

View File

@ -2,9 +2,8 @@
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using Artemis.Core.VisualScripting;
namespace Artemis.VisualScripting.Model namespace Artemis.Core
{ {
public abstract class PinCollection : IPinCollection public abstract class PinCollection : IPinCollection
{ {

View File

@ -1,4 +1,4 @@
namespace Artemis.VisualScripting.Model namespace Artemis.Core
{ {
public enum PinDirection public enum PinDirection
{ {

View File

@ -2,12 +2,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Ninject.Factories; using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens.ProfileEditor.Conditions; using Artemis.UI.Screens.ProfileEditor.Conditions;
using Artemis.UI.Shared; using Artemis.UI.Shared;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using Artemis.VisualScripting.Model;
using Artemis.VisualScripting.Services;
using Stylet; using Stylet;
namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
@ -16,33 +15,24 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
{ {
private readonly IDataModelConditionsVmFactory _dataModelConditionsVmFactory; private readonly IDataModelConditionsVmFactory _dataModelConditionsVmFactory;
private readonly IProfileEditorService _profileEditorService; private readonly IProfileEditorService _profileEditorService;
private readonly INodeService _nodeService;
private RenderProfileElement _renderProfileElement; private RenderProfileElement _renderProfileElement;
private bool _displayStartHint; private bool _displayStartHint;
private bool _isEventCondition; private bool _isEventCondition;
public DisplayConditionsViewModel(IProfileEditorService profileEditorService, IDataModelConditionsVmFactory dataModelConditionsVmFactory) public DisplayConditionsViewModel(IProfileEditorService profileEditorService, INodeService nodeService, IDataModelConditionsVmFactory dataModelConditionsVmFactory)
{ {
_profileEditorService = profileEditorService; _profileEditorService = profileEditorService;
_nodeService = nodeService;
_dataModelConditionsVmFactory = dataModelConditionsVmFactory; _dataModelConditionsVmFactory = dataModelConditionsVmFactory;
AvailableNodes = _nodeService.AvailableNodes; AvailableNodes = _nodeService.AvailableNodes;
Script = new Script<bool>("Display Condition (TODO)", "TODO"); Script = new NodeScript<bool>("Display Condition (TODO)", "TODO");
} }
#region TODO
private static NodeService _nodeService; private NodeScript<bool> _script;
public NodeScript<bool> Script
static DisplayConditionsViewModel()
{
_nodeService = new NodeService();
_nodeService.InitializeNodes();
}
#endregion
private Script<bool> _script;
public Script<bool> Script
{ {
get => _script; get => _script;
private set => SetAndNotify(ref _script, value); private set => SetAndNotify(ref _script, value);
@ -161,7 +151,7 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
// renderProfileElement.DisplayCondition = new DataModelConditionGroup(null); // renderProfileElement.DisplayCondition = new DataModelConditionGroup(null);
if (renderProfileElement.DisplayCondition == null) if (renderProfileElement.DisplayCondition == null)
renderProfileElement.DisplayCondition = new Script<bool>("Display Condition (TODO)", "-"); renderProfileElement.DisplayCondition = new NodeScript<bool>("Display Condition (TODO)", "-");
//List<Module> modules = new(); //List<Module> modules = new();
//if (_profileEditorService.SelectedProfileConfiguration?.Module != null) //if (_profileEditorService.SelectedProfileConfiguration?.Module != null)

View File

@ -172,6 +172,7 @@ namespace Artemis.UI.Screens
_builtInRegistrationService.RegisterBuiltInDataModelDisplays(); _builtInRegistrationService.RegisterBuiltInDataModelDisplays();
_builtInRegistrationService.RegisterBuiltInDataModelInputs(); _builtInRegistrationService.RegisterBuiltInDataModelInputs();
_builtInRegistrationService.RegisterBuiltInPropertyEditors(); _builtInRegistrationService.RegisterBuiltInPropertyEditors();
_builtInRegistrationService.RegisterBuiltInNodeTypes();
_window = (MaterialWindow) View; _window = (MaterialWindow) View;

View File

@ -10,6 +10,7 @@ using Artemis.UI.Ninject;
using Artemis.UI.Providers; using Artemis.UI.Providers;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using Artemis.UI.SkiaSharp; using Artemis.UI.SkiaSharp;
using Artemis.VisualScripting.Nodes;
using Serilog; using Serilog;
namespace Artemis.UI.Services namespace Artemis.UI.Services
@ -25,6 +26,7 @@ namespace Artemis.UI.Services
private readonly IMessageService _messageService; private readonly IMessageService _messageService;
private readonly IWebServerService _webServerService; private readonly IWebServerService _webServerService;
private readonly IRgbService _rgbService; private readonly IRgbService _rgbService;
private readonly INodeService _nodeService;
private readonly ISettingsService _settingsService; private readonly ISettingsService _settingsService;
private bool _registeredBuiltInDataModelDisplays; private bool _registeredBuiltInDataModelDisplays;
private bool _registeredBuiltInDataModelInputs; private bool _registeredBuiltInDataModelInputs;
@ -40,6 +42,7 @@ namespace Artemis.UI.Services
IMessageService messageService, IMessageService messageService,
IWebServerService webServerService, IWebServerService webServerService,
IRgbService rgbService, IRgbService rgbService,
INodeService nodeService,
ISettingsService settingsService) ISettingsService settingsService)
{ {
_logger = logger; _logger = logger;
@ -51,6 +54,7 @@ namespace Artemis.UI.Services
_messageService = messageService; _messageService = messageService;
_webServerService = webServerService; _webServerService = webServerService;
_rgbService = rgbService; _rgbService = rgbService;
_nodeService = nodeService;
_settingsService = settingsService; _settingsService = settingsService;
LoadPluginModules(); LoadPluginModules();
@ -113,6 +117,12 @@ namespace Artemis.UI.Services
_webServerService.AddController<RemoteController>(Constants.CorePlugin.Features.First().Instance!); _webServerService.AddController<RemoteController>(Constants.CorePlugin.Features.First().Instance!);
} }
public void RegisterBuiltInNodeTypes()
{
foreach (Type nodeType in typeof(SumIntegersNode).Assembly.GetTypes().Where(t => typeof(INode).IsAssignableFrom(t) && t.IsPublic && !t.IsAbstract && !t.IsInterface))
_nodeService.RegisterNodeType(Constants.CorePlugin, nodeType);
}
/// <inheritdoc /> /// <inheritdoc />
public void ApplyPreferredGraphicsContext() public void ApplyPreferredGraphicsContext()
{ {
@ -167,5 +177,6 @@ namespace Artemis.UI.Services
void RegisterProviders(); void RegisterProviders();
void RegisterControllers(); void RegisterControllers();
void ApplyPreferredGraphicsContext(); void ApplyPreferredGraphicsContext();
void RegisterBuiltInNodeTypes();
} }
} }

View File

@ -1482,7 +1482,8 @@
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Artemis.Core": "1.0.0", "Artemis.Core": "1.0.0",
"JetBrains.Annotations": "2021.1.0" "JetBrains.Annotations": "2021.1.0",
"Stylet": "1.3.6"
} }
} }
} }

View File

@ -37,6 +37,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2021.1.0" /> <PackageReference Include="JetBrains.Annotations" Version="2021.1.0" />
<PackageReference Include="Stylet" Version="1.3.6" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,8 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using Artemis.Core.VisualScripting; using Artemis.Core;
using Artemis.VisualScripting.Model;
namespace Artemis.VisualScripting.Editor.Controls namespace Artemis.VisualScripting.Editor.Controls
{ {
@ -15,11 +14,11 @@ namespace Artemis.VisualScripting.Editor.Controls
#region Dependency Properties #region Dependency Properties
public static readonly DependencyProperty ScriptProperty = DependencyProperty.Register( public static readonly DependencyProperty ScriptProperty = DependencyProperty.Register(
"Script", typeof(IScript), typeof(VisualScriptEditor), new PropertyMetadata(default(IScript))); "Script", typeof(INodeScript), typeof(VisualScriptEditor), new PropertyMetadata(default(INodeScript)));
public IScript Script public INodeScript Script
{ {
get => (IScript)GetValue(ScriptProperty); get => (INodeScript)GetValue(ScriptProperty);
set => SetValue(ScriptProperty, value); set => SetValue(ScriptProperty, value);
} }

View File

@ -5,7 +5,7 @@ using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Input; using System.Windows.Input;
using Artemis.VisualScripting.Model; using Artemis.Core;
namespace Artemis.VisualScripting.Editor.Controls namespace Artemis.VisualScripting.Editor.Controls
{ {

View File

@ -4,8 +4,8 @@ using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using Artemis.Core;
using Artemis.VisualScripting.Editor.Controls.Wrapper; using Artemis.VisualScripting.Editor.Controls.Wrapper;
using Artemis.VisualScripting.Model;
namespace Artemis.VisualScripting.Editor.Controls namespace Artemis.VisualScripting.Editor.Controls
{ {

View File

@ -6,10 +6,10 @@ using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using Artemis.Core.VisualScripting; using Artemis.Core;
using Artemis.VisualScripting.Editor.Controls.Wrapper; using Artemis.VisualScripting.Editor.Controls.Wrapper;
using Artemis.VisualScripting.Model;
using Artemis.VisualScripting.ViewModel; using Artemis.VisualScripting.ViewModel;
using VisualScript = Artemis.VisualScripting.Editor.Controls.Wrapper.VisualScript;
namespace Artemis.VisualScripting.Editor.Controls namespace Artemis.VisualScripting.Editor.Controls
{ {
@ -58,11 +58,11 @@ namespace Artemis.VisualScripting.Editor.Controls
#region Dependency Properties #region Dependency Properties
public static readonly DependencyProperty ScriptProperty = DependencyProperty.Register( public static readonly DependencyProperty ScriptProperty = DependencyProperty.Register(
"Script", typeof(IScript), typeof(VisualScriptPresenter), new PropertyMetadata(default(IScript), ScriptChanged)); "Script", typeof(INodeScript), typeof(VisualScriptPresenter), new PropertyMetadata(default(INodeScript), ScriptChanged));
public IScript Script public INodeScript Script
{ {
get => (IScript)GetValue(ScriptProperty); get => (INodeScript)GetValue(ScriptProperty);
set => SetValue(ScriptProperty, value); set => SetValue(ScriptProperty, value);
} }
@ -188,7 +188,7 @@ namespace Artemis.VisualScripting.Editor.Controls
{ {
if (d is not VisualScriptPresenter scriptPresenter) return; if (d is not VisualScriptPresenter scriptPresenter) return;
scriptPresenter.ScriptChanged(args.NewValue is not Script script ? null : new VisualScript(script, scriptPresenter.SurfaceSize, scriptPresenter.GridSize)); scriptPresenter.ScriptChanged(args.NewValue is not NodeScript script ? null : new VisualScript(script, scriptPresenter.SurfaceSize, scriptPresenter.GridSize));
} }
private void ScriptChanged(VisualScript newScript) private void ScriptChanged(VisualScript newScript)

View File

@ -4,7 +4,7 @@ using System.Collections.ObjectModel;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
using Artemis.Core.VisualScripting; using Artemis.Core;
using Artemis.VisualScripting.Events; using Artemis.VisualScripting.Events;
using Artemis.VisualScripting.ViewModel; using Artemis.VisualScripting.ViewModel;
@ -19,7 +19,7 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
private double _nodeDragAccumulationX; private double _nodeDragAccumulationX;
private double _nodeDragAccumulationY; private double _nodeDragAccumulationY;
public IScript Script { get; } public INodeScript Script { get; }
public int SurfaceSize { get; } public int SurfaceSize { get; }
public int GridSize { get; } public int GridSize { get; }
@ -56,7 +56,7 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
#region Constructors #region Constructors
public VisualScript(IScript script, int surfaceSize, int gridSize) public VisualScript(INodeScript script, int surfaceSize, int gridSize)
{ {
this.Script = script; this.Script = script;
this.SurfaceSize = surfaceSize; this.SurfaceSize = surfaceSize;

View File

@ -1,6 +1,5 @@
using System; using System;
using Artemis.Core.VisualScripting; using Artemis.Core;
using Artemis.VisualScripting.Model;
using Artemis.VisualScripting.ViewModel; using Artemis.VisualScripting.ViewModel;
namespace Artemis.VisualScripting.Editor.Controls.Wrapper namespace Artemis.VisualScripting.Editor.Controls.Wrapper

View File

@ -3,10 +3,8 @@ using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using Artemis.Core.VisualScripting; using Artemis.Core;
using Artemis.VisualScripting.Events; using Artemis.VisualScripting.Events;
using Artemis.VisualScripting.Internal;
using Artemis.VisualScripting.Model;
using Artemis.VisualScripting.ViewModel; using Artemis.VisualScripting.ViewModel;
namespace Artemis.VisualScripting.Editor.Controls.Wrapper namespace Artemis.VisualScripting.Editor.Controls.Wrapper
@ -255,7 +253,7 @@ namespace Artemis.VisualScripting.Editor.Controls.Wrapper
Script.RemoveNode(this); Script.RemoveNode(this);
} }
private bool RemoveCanExecute() => Node is not IExitNode; private bool RemoveCanExecute() => !Node.IsExitNode;
#endregion #endregion
} }

View File

@ -2,10 +2,9 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
using Artemis.Core.VisualScripting; using Artemis.Core;
using Artemis.VisualScripting.Events; using Artemis.VisualScripting.Events;
using Artemis.VisualScripting.Internal; using Artemis.VisualScripting.Internal;
using Artemis.VisualScripting.Model;
using Artemis.VisualScripting.ViewModel; using Artemis.VisualScripting.ViewModel;
namespace Artemis.VisualScripting.Editor.Controls.Wrapper namespace Artemis.VisualScripting.Editor.Controls.Wrapper

View File

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using Artemis.Core.VisualScripting; using Artemis.Core;
using Artemis.VisualScripting.ViewModel; using Artemis.VisualScripting.ViewModel;
namespace Artemis.VisualScripting.Editor.Controls.Wrapper namespace Artemis.VisualScripting.Editor.Controls.Wrapper

View File

@ -6,8 +6,5 @@
<ResourceDictionary Source="Styles/VisualScriptNodePresenter.xaml" /> <ResourceDictionary Source="Styles/VisualScriptNodePresenter.xaml" />
<ResourceDictionary Source="Styles/VisualScriptPinPresenter.xaml" /> <ResourceDictionary Source="Styles/VisualScriptPinPresenter.xaml" />
<ResourceDictionary Source="Styles/VisualScriptPresenter.xaml" /> <ResourceDictionary Source="Styles/VisualScriptPresenter.xaml" />
<!-- TODO: Load external -->
<ResourceDictionary Source="../Nodes/Styles/StaticValueNodes.xaml" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>

View File

@ -1,10 +1,10 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls" xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls"
xmlns:model="clr-namespace:Artemis.VisualScripting.Model"> xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core">
<DataTemplate x:Key="TemplateNodeItem" <DataTemplate x:Key="TemplateNodeItem"
DataType="{x:Type model:NodeData}"> DataType="{x:Type core:NodeData}">
<TextBlock Text="{Binding Name}" /> <TextBlock Text="{Binding Name}" />
</DataTemplate> </DataTemplate>

View File

@ -2,7 +2,8 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls" xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls"
xmlns:wrapper="clr-namespace:Artemis.VisualScripting.Editor.Controls.Wrapper" xmlns:wrapper="clr-namespace:Artemis.VisualScripting.Editor.Controls.Wrapper"
xmlns:model="clr-namespace:Artemis.VisualScripting.Model"> xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core"
xmlns:s="https://github.com/canton7/Stylet">
<Style x:Key="StyleButtonPinsModify" <Style x:Key="StyleButtonPinsModify"
TargetType="Button"> TargetType="Button">
@ -73,7 +74,7 @@
<Setter Property="ItemTemplate"> <Setter Property="ItemTemplate">
<Setter.Value> <Setter.Value>
<DataTemplate DataType="{x:Type model:Pin}"> <DataTemplate DataType="{x:Type core:Pin}">
<controls:VisualScriptPinPresenter Margin="0,5,0,3" <controls:VisualScriptPinPresenter Margin="0,5,0,3"
Pin="{Binding .}" /> Pin="{Binding .}" />
</DataTemplate> </DataTemplate>
@ -88,7 +89,7 @@
<Setter Property="ItemTemplate"> <Setter Property="ItemTemplate">
<Setter.Value> <Setter.Value>
<DataTemplate DataType="{x:Type model:Pin}"> <DataTemplate DataType="{x:Type core:Pin}">
<controls:VisualScriptPinPresenter Margin="0,5,0,3" <controls:VisualScriptPinPresenter Margin="0,5,0,3"
Pin="{Binding .}" /> Pin="{Binding .}" />
</DataTemplate> </DataTemplate>
@ -108,7 +109,7 @@
Style="{StaticResource StylePinListInput}" Style="{StaticResource StylePinListInput}"
ItemsSource="{Binding Pins}"> ItemsSource="{Binding Pins}">
<ItemsControl.ItemTemplate> <ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type model:Pin}"> <DataTemplate DataType="{x:Type core:Pin}">
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal"> <StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
<controls:VisualScriptPinPresenter Margin="0,5,-3,3" <controls:VisualScriptPinPresenter Margin="0,5,-3,3"
Pin="{Binding .}" /> Pin="{Binding .}" />
@ -141,7 +142,7 @@
Style="{StaticResource StylePinListOutput}" Style="{StaticResource StylePinListOutput}"
ItemsSource="{Binding Pins}"> ItemsSource="{Binding Pins}">
<ItemsControl.ItemTemplate> <ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type model:Pin}"> <DataTemplate DataType="{x:Type core:Pin}">
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal"> <StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<Button Style="{StaticResource StyleButtonPinsModify}" <Button Style="{StaticResource StyleButtonPinsModify}"
Command="{Binding DataContext.RemovePinCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" Command="{Binding DataContext.RemovePinCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"
@ -207,8 +208,7 @@
</Border> </Border>
<Border x:Name="BrdCustomView" Grid.Column="1"> <Border x:Name="BrdCustomView" Grid.Column="1">
<ContentControl Content="{Binding Node.Node.CustomViewModel, RelativeSource={RelativeSource TemplatedParent}}" <ContentControl s:View.Model="{Binding Node.CustomViewModel}"/>
ContentTemplate="{Binding Node.Node.CustomView, RelativeSource={RelativeSource TemplatedParent}}"/>
</Border> </Border>
<Border x:Name="BrdOutputPins" Grid.Column="2"> <Border x:Name="BrdOutputPins" Grid.Column="2">

View File

@ -2,7 +2,8 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=System.Runtime" xmlns:system="clr-namespace:System;assembly=System.Runtime"
xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls" xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls"
xmlns:model="clr-namespace:Artemis.VisualScripting.Model;assembly=Artemis.Core"> xmlns:model="clr-namespace:Artemis.VisualScripting.Model;assembly=Artemis.Core"
xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core">
<ControlTemplate x:Key="TemplateVisualScriptPinPresenterInput" <ControlTemplate x:Key="TemplateVisualScriptPinPresenterInput"
TargetType="{x:Type controls:VisualScriptPinPresenter}"> TargetType="{x:Type controls:VisualScriptPinPresenter}">
@ -75,7 +76,7 @@
<Setter Property="Template" Value="{StaticResource TemplateVisualScriptPinPresenterInput}" /> <Setter Property="Template" Value="{StaticResource TemplateVisualScriptPinPresenterInput}" />
<Style.Triggers> <Style.Triggers>
<DataTrigger Binding="{Binding Pin.Pin.Direction, RelativeSource={RelativeSource Self}}" Value="{x:Static model:PinDirection.Output}"> <DataTrigger Binding="{Binding Pin.Pin.Direction, RelativeSource={RelativeSource Self}}" Value="{x:Static core:PinDirection.Output}">
<Setter Property="Padding" Value="6,0,0,0" /> <Setter Property="Padding" Value="6,0,0,0" />
<Setter Property="Template" Value="{StaticResource TemplateVisualScriptPinPresenterOutput}" /> <Setter Property="Template" Value="{StaticResource TemplateVisualScriptPinPresenterOutput}" />
</DataTrigger> </DataTrigger>

View File

@ -1,5 +1,5 @@
using System; using System;
using Artemis.VisualScripting.Model; using Artemis.Core;
namespace Artemis.VisualScripting.Internal namespace Artemis.VisualScripting.Internal
{ {

View File

@ -1,10 +1,9 @@
using System.Collections; using System.Collections;
using Artemis.VisualScripting.Attributes; using Artemis.Core;
using Artemis.VisualScripting.Model;
namespace Artemis.VisualScripting.Nodes namespace Artemis.VisualScripting.Nodes
{ {
[UI("Greater than", "Checks if the first input is greater than the second.")] [Node("Greater than", "Checks if the first input is greater than the second.")]
public class GreaterThanNode : Node public class GreaterThanNode : Node
{ {
#region Properties & Fields #region Properties & Fields
@ -45,7 +44,7 @@ namespace Artemis.VisualScripting.Nodes
#endregion #endregion
} }
[UI("Less than", "Checks if the first input is less than the second.")] [Node("Less than", "Checks if the first input is less than the second.")]
public class LessThanNode : Node public class LessThanNode : Node
{ {
#region Properties & Fields #region Properties & Fields
@ -86,7 +85,7 @@ namespace Artemis.VisualScripting.Nodes
#endregion #endregion
} }
[UI("Equals", "Checks if the two inputs are equals.")] [Node("Equals", "Checks if the two inputs are equals.")]
public class EqualsNode : Node public class EqualsNode : Node
{ {
#region Properties & Fields #region Properties & Fields
@ -127,7 +126,7 @@ namespace Artemis.VisualScripting.Nodes
#endregion #endregion
} }
[UI("Negate", "Negates the boolean.")] [Node("Negate", "Negates the boolean.")]
public class NegateNode : Node public class NegateNode : Node
{ {
#region Properties & Fields #region Properties & Fields

View File

@ -1,9 +1,8 @@
using Artemis.VisualScripting.Attributes; using Artemis.Core;
using Artemis.VisualScripting.Model;
namespace Artemis.VisualScripting.Nodes namespace Artemis.VisualScripting.Nodes
{ {
[UI("To String", "Converts the input to a string.")] [Node("To String", "Converts the input to a string.")]
public class ConvertToStringNode : Node public class ConvertToStringNode : Node
{ {
#region Properties & Fields #region Properties & Fields
@ -35,7 +34,7 @@ namespace Artemis.VisualScripting.Nodes
#endregion #endregion
} }
[UI("To Integer", "Converts the input to an integer.")] [Node("To Integer", "Converts the input to an integer.")]
public class ConvertToIntegerNode : Node public class ConvertToIntegerNode : Node
{ {
#region Properties & Fields #region Properties & Fields
@ -70,7 +69,7 @@ namespace Artemis.VisualScripting.Nodes
#endregion #endregion
} }
[UI("To Double", "Converts the input to a double.")] [Node("To Double", "Converts the input to a double.")]
public class ConvertToDoubleNode : Node public class ConvertToDoubleNode : Node
{ {
#region Properties & Fields #region Properties & Fields

View File

@ -0,0 +1,15 @@
using Stylet;
namespace Artemis.VisualScripting.Nodes.CustomViewModels
{
public class StaticDoubleValueNodeCustomViewModel : PropertyChangedBase
{
private double _input;
public double Input
{
get => _input;
set => SetAndNotify(ref _input, value);
}
}
}

View File

@ -0,0 +1,15 @@
using Stylet;
namespace Artemis.VisualScripting.Nodes.CustomViewModels
{
public class StaticIntegerValueNodeCustomViewModel : PropertyChangedBase
{
private int _input;
public int Input
{
get => _input;
set => SetAndNotify(ref _input, value);
}
}
}

View File

@ -0,0 +1,15 @@
using Stylet;
namespace Artemis.VisualScripting.Nodes.CustomViewModels
{
public class StaticStringValueNodeCustomViewModel : PropertyChangedBase
{
private string _input;
public string Input
{
get => _input;
set => SetAndNotify(ref _input, value);
}
}
}

View File

@ -0,0 +1,12 @@
<UserControl x:Class="Artemis.VisualScripting.Nodes.CustomViews.StaticDoubleValueNodeCustomView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.VisualScripting.Nodes.CustomViewModels"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<TextBox VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Text="{Binding Input}" />
</UserControl>

View File

@ -0,0 +1,12 @@
<UserControl x:Class="Artemis.VisualScripting.Nodes.CustomViews.StaticIntegerValueNodeCustomView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.VisualScripting.Nodes.CustomViewModels"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<TextBox VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Text="{Binding Input}" />
</UserControl>

View File

@ -0,0 +1,12 @@
<UserControl x:Class="Artemis.VisualScripting.Nodes.CustomViews.StaticStringValueNodeCustomView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.VisualScripting.Nodes.CustomViewModels"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<TextBox VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Text="{Binding Input}" />
</UserControl>

View File

@ -1,10 +1,9 @@
using System.Windows; using Artemis.Core;
using Artemis.VisualScripting.Attributes; using Artemis.VisualScripting.Nodes.CustomViewModels;
using Artemis.VisualScripting.Model;
namespace Artemis.VisualScripting.Nodes namespace Artemis.VisualScripting.Nodes
{ {
[UI("Integer-Value", "Outputs an configurable integer value.")] [Node("Integer-Value", "Outputs an configurable integer value.")]
public class StaticIntegerValueNode : Node public class StaticIntegerValueNode : Node
{ {
#region Properties & Fields #region Properties & Fields
@ -21,7 +20,7 @@ namespace Artemis.VisualScripting.Nodes
: base("Integer", "Outputs an configurable integer value.") : base("Integer", "Outputs an configurable integer value.")
{ {
Output = CreateOutputPin<int>(); Output = CreateOutputPin<int>();
RegisterCustomView(Application.Current.FindResource("StaticValueCustomViewTemplate") as DataTemplate, _customViewModel); RegisterCustomViewModel<StaticIntegerValueNodeCustomViewModel>();
} }
#endregion #endregion
@ -36,7 +35,7 @@ namespace Artemis.VisualScripting.Nodes
#endregion #endregion
} }
[UI("Double-Value", "Outputs a configurable double value.")] [Node("Double-Value", "Outputs a configurable double value.")]
public class StaticDoubleValueNode : Node public class StaticDoubleValueNode : Node
{ {
#region Properties & Fields #region Properties & Fields
@ -53,7 +52,7 @@ namespace Artemis.VisualScripting.Nodes
: base("Double", "Outputs a configurable double value.") : base("Double", "Outputs a configurable double value.")
{ {
Output = CreateOutputPin<double>(); Output = CreateOutputPin<double>();
RegisterCustomView(Application.Current.FindResource("StaticValueCustomViewTemplate") as DataTemplate, _customViewModel); RegisterCustomViewModel<StaticDoubleValueNodeCustomViewModel>();
} }
#endregion #endregion
@ -68,7 +67,7 @@ namespace Artemis.VisualScripting.Nodes
#endregion #endregion
} }
[UI("String-Value", "Outputs a configurable string value.")] [Node("String-Value", "Outputs a configurable string value.")]
public class StaticStringValueNode : Node public class StaticStringValueNode : Node
{ {
#region Properties & Fields #region Properties & Fields
@ -85,7 +84,7 @@ namespace Artemis.VisualScripting.Nodes
: base("String", "Outputs a configurable string value.") : base("String", "Outputs a configurable string value.")
{ {
Output = CreateOutputPin<string>(); Output = CreateOutputPin<string>();
RegisterCustomView(Application.Current.FindResource("StaticValueCustomViewTemplate") as DataTemplate, _customViewModel); RegisterCustomViewModel<StaticStringValueNodeCustomViewModel>();
} }
#endregion #endregion
@ -102,20 +101,7 @@ namespace Artemis.VisualScripting.Nodes
#region CustomViewModels #region CustomViewModels
public class StaticIntegerValueNodeCustomViewModel
{
public int Input { get; set; }
}
public class StaticDoubleValueNodeCustomViewModel
{
public double Input { get; set; }
}
public class StaticStringValueNodeCustomViewModel
{
public string Input { get; set; }
}
#endregion #endregion
} }

View File

@ -1,10 +1,9 @@
using System.Linq; using System.Linq;
using Artemis.VisualScripting.Attributes; using Artemis.Core;
using Artemis.VisualScripting.Model;
namespace Artemis.VisualScripting.Nodes namespace Artemis.VisualScripting.Nodes
{ {
[UI("Format", "Formats the input string.")] [Node("Format", "Formats the input string.")]
public class StringFormatNode : Node public class StringFormatNode : Node
{ {
#region Properties & Fields #region Properties & Fields

View File

@ -1,12 +0,0 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:nodes="clr-namespace:Artemis.VisualScripting.Nodes">
<DataTemplate x:Key="StaticValueCustomViewTemplate"
DataType="{x:Type nodes:StaticIntegerValueNodeCustomViewModel}">
<TextBox VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Text="{Binding Input}" />
</DataTemplate>
</ResourceDictionary>

View File

@ -1,10 +1,9 @@
using System.Linq; using System.Linq;
using Artemis.VisualScripting.Attributes; using Artemis.Core;
using Artemis.VisualScripting.Model;
namespace Artemis.VisualScripting.Nodes namespace Artemis.VisualScripting.Nodes
{ {
[UI("Sum (Integer)", "Sums the connected integer values.")] [Node("Sum (Integer)", "Sums the connected integer values.")]
public class SumIntegersNode : Node public class SumIntegersNode : Node
{ {
#region Properties & Fields #region Properties & Fields
@ -36,7 +35,7 @@ namespace Artemis.VisualScripting.Nodes
#endregion #endregion
} }
[UI("Sum (Double)", "Sums the connected double values.")] [Node("Sum (Double)", "Sums the connected double values.")]
public class SumDoublesNode : Node public class SumDoublesNode : Node
{ {
#region Properties & Fields #region Properties & Fields

View File

@ -1,59 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using Artemis.Core.VisualScripting;
using Artemis.VisualScripting.Attributes;
using Artemis.VisualScripting.Model;
namespace Artemis.VisualScripting.Services
{
//TODO DarthAffe 09.07.2021: Make this Static?
public class NodeService
{
#region Constants
private static readonly Type TYPE_NODE = typeof(INode);
#endregion
#region Properties & Fields
private Dictionary<Type, NodeData> _nodeData { get; } = new();
public IReadOnlyDictionary<Type, NodeData> NodeData => new ReadOnlyDictionary<Type, NodeData>(_nodeData);
public IEnumerable<NodeData> AvailableNodes => _nodeData.Values;
#endregion
#region Methods
public void InitializeNodes()
{
foreach (Type nodeType in typeof(NodeService).Assembly.GetTypes().Where(t => typeof(INode).IsAssignableFrom(t) && t.IsPublic && !t.IsAbstract && !t.IsInterface))
InitializeNode(nodeType);
}
public void InitializeNode<T>()
where T : INode
=> InitializeNode(typeof(T));
public void InitializeNode(Type nodeType)
{
if (!TYPE_NODE.IsAssignableFrom(nodeType)) throw new ArgumentException("Node has to be a base type of the Node-Type.", nameof(nodeType));
if (_nodeData.ContainsKey(nodeType)) return;
UIAttribute uiAttribute = nodeType.GetCustomAttribute<UIAttribute>();
string name = uiAttribute?.Name ?? nodeType.Name;
string description = uiAttribute?.Description ?? string.Empty;
string category = uiAttribute?.Category ?? string.Empty;
NodeData nodeData = new(nodeType, name, description, category, () => CreateNode(nodeType));
_nodeData.Add(nodeType, nodeData);
}
private INode CreateNode(Type nodeType) => Activator.CreateInstance(nodeType) as INode;
#endregion
}
}

View File

@ -8,6 +8,15 @@
"resolved": "2021.1.0", "resolved": "2021.1.0",
"contentHash": "n9JSw5Z+F+6gp9vSv4aLH6p/bx3GAYA6FZVq1wJq/TJySv/kPgFKLGFeS7A8Xa5X4/GWorh5gd43yjamUgnBNA==" "contentHash": "n9JSw5Z+F+6gp9vSv4aLH6p/bx3GAYA6FZVq1wJq/TJySv/kPgFKLGFeS7A8Xa5X4/GWorh5gd43yjamUgnBNA=="
}, },
"Stylet": {
"type": "Direct",
"requested": "[1.3.6, )",
"resolved": "1.3.6",
"contentHash": "SISR+DsPrgBww3AI5FtHx1tD9VkEfJWZYu+ykq5EFM2o7Se9zxNR6FAa2g5QadQa90NKMYxn/VZEQRDo7/pdkw==",
"dependencies": {
"System.Drawing.Common": "4.6.0"
}
},
"Castle.Core": { "Castle.Core": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.2.0", "resolved": "4.2.0",
@ -87,6 +96,14 @@
"System.Runtime": "4.3.0" "System.Runtime": "4.3.0"
} }
}, },
"Microsoft.Win32.SystemEvents": {
"type": "Transitive",
"resolved": "4.6.0",
"contentHash": "Edg+pFW5C8WJb680Za2kTV8TqUi6Ahl/WldRVoOVJ23UQLpDHFspa+umgFjkWZw24ETsU99Cg+ErZz683M4chg==",
"dependencies": {
"Microsoft.NETCore.Platforms": "3.0.0"
}
},
"NETStandard.Library": { "NETStandard.Library": {
"type": "Transitive", "type": "Transitive",
"resolved": "1.6.1", "resolved": "1.6.1",
@ -504,6 +521,15 @@
"System.Runtime": "4.3.0" "System.Runtime": "4.3.0"
} }
}, },
"System.Drawing.Common": {
"type": "Transitive",
"resolved": "4.6.0",
"contentHash": "2A3spjjoPZnvpVh/sDTzd+0H8ZqTdr+hH/6obB8MMfG81EJ85PmxCKDBxhBVQiA25PliKAZ1sKogDcq9mSnFEA==",
"dependencies": {
"Microsoft.NETCore.Platforms": "3.0.0",
"Microsoft.Win32.SystemEvents": "4.6.0"
}
},
"System.Dynamic.Runtime": { "System.Dynamic.Runtime": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.3.0", "resolved": "4.3.0",