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

Nodes - Added XML docs for remaining types

Nodes - Fully implemented nullable reference types
This commit is contained in:
Robert 2021-09-25 21:35:54 +02:00
parent c1dab91c16
commit c21acf87a7
30 changed files with 644 additions and 265 deletions

View File

@ -93,6 +93,13 @@ namespace Artemis.Core
} }
} }
/// <summary>
/// Returns the index of the provided element inside the read only collection
/// </summary>
/// <typeparam name="T">The type of element to find</typeparam>
/// <param name="self">The collection to search in</param>
/// <param name="elementToFind">The element to find</param>
/// <returns>If found, the index of the element to find; otherwise -1</returns>
public static int IndexOf<T>(this IReadOnlyCollection<T> self, T elementToFind) public static int IndexOf<T>(this IReadOnlyCollection<T> self, T elementToFind)
{ {
int i = 0; int i = 0;
@ -102,6 +109,7 @@ namespace Artemis.Core
return i; return i;
i++; i++;
} }
return -1; return -1;
} }
} }

View File

@ -6,6 +6,9 @@ using Artemis.Storage.Entities.Profile.Conditions;
namespace Artemis.Core namespace Artemis.Core
{ {
/// <summary>
/// Represents a condition that is based on a <see cref="DataModelEvent" />
/// </summary>
public class EventCondition : CorePropertyChanged, INodeScriptCondition public class EventCondition : CorePropertyChanged, INodeScriptCondition
{ {
private readonly string _displayName; private readonly string _displayName;
@ -78,7 +81,7 @@ namespace Artemis.Core
} }
else else
{ {
_eventNode = new EventDefaultNode() {X = -300}; _eventNode = new EventDefaultNode {X = -300};
_eventNode.UpdateDataModelEvent(dataModelEvent); _eventNode.UpdateDataModelEvent(dataModelEvent);
} }

View File

@ -3,11 +3,17 @@ using Artemis.Storage.Entities.Profile.Conditions;
namespace Artemis.Core namespace Artemis.Core
{ {
/// <summary>
/// Represents a condition that is based on a data model value
/// </summary>
public class StaticCondition : CorePropertyChanged, INodeScriptCondition public class StaticCondition : CorePropertyChanged, INodeScriptCondition
{ {
private readonly StaticConditionEntity _entity;
private readonly string _displayName; private readonly string _displayName;
private readonly StaticConditionEntity _entity;
/// <summary>
/// Creates a new instance of the <see cref="StaticCondition" /> class
/// </summary>
public StaticCondition(ProfileElement profileElement) public StaticCondition(ProfileElement profileElement)
{ {
_entity = new StaticConditionEntity(); _entity = new StaticConditionEntity();

View File

@ -4,7 +4,7 @@ using System.Collections.Generic;
namespace Artemis.Core namespace Artemis.Core
{ {
/// <summary> /// <summary>
/// Represents a data model event that can trigger <see cref="DataModelConditionEvent" />s. /// Represents an event that is part of a data model
/// </summary> /// </summary>
public interface IDataModelEvent public interface IDataModelEvent
{ {

View File

@ -82,7 +82,6 @@ namespace Artemis.Core
private TimeSpan _position; private TimeSpan _position;
private TimeSpan _lastDelta; private TimeSpan _lastDelta;
private TimeLineEventOverlapMode _eventOverlapMode;
private TimelinePlayMode _playMode; private TimelinePlayMode _playMode;
private TimelineStopMode _stopMode; private TimelineStopMode _stopMode;
private readonly List<Timeline> _extraTimelines; private readonly List<Timeline> _extraTimelines;

View File

@ -114,17 +114,20 @@ namespace Artemis.Core.Modules
private readonly List<(DefaultCategoryName, string)> _defaultProfilePaths = new(); private readonly List<(DefaultCategoryName, string)> _defaultProfilePaths = new();
private readonly List<(DefaultCategoryName, string)> _pendingDefaultProfilePaths = new(); private readonly List<(DefaultCategoryName, string)> _pendingDefaultProfilePaths = new();
protected Module()
{
DefaultProfilePaths = new ReadOnlyCollection<(DefaultCategoryName, string)>(_defaultProfilePaths);
HiddenProperties = new(HiddenPropertiesList);
}
/// <summary> /// <summary>
/// Gets a list of all properties ignored at runtime using <c>IgnoreProperty(x => x.y)</c> /// Gets a list of all properties ignored at runtime using <c>IgnoreProperty(x => x.y)</c>
/// </summary> /// </summary>
protected internal readonly List<PropertyInfo> HiddenPropertiesList = new(); protected internal readonly List<PropertyInfo> HiddenPropertiesList = new();
/// <summary>
/// The base constructor of the <see cref="Module" /> class.
/// </summary>
protected Module()
{
DefaultProfilePaths = new ReadOnlyCollection<(DefaultCategoryName, string)>(_defaultProfilePaths);
HiddenProperties = new ReadOnlyCollection<PropertyInfo>(HiddenPropertiesList);
}
/// <summary> /// <summary>
/// Gets a read only collection of default profile paths /// Gets a read only collection of default profile paths
/// </summary> /// </summary>
@ -237,7 +240,7 @@ namespace Artemis.Core.Modules
/// <returns></returns> /// <returns></returns>
public virtual DataModelPropertyAttribute GetDataModelDescription() public virtual DataModelPropertyAttribute GetDataModelDescription()
{ {
return new() {Name = Plugin.Info.Name, Description = Plugin.Info.Description}; return new DataModelPropertyAttribute {Name = Plugin.Info.Name, Description = Plugin.Info.Description};
} }
/// <summary> /// <summary>

View File

@ -44,9 +44,12 @@ namespace Artemis.Core.ScriptingProviders
/// </summary> /// </summary>
public abstract class ScriptingProvider : PluginFeature public abstract class ScriptingProvider : PluginFeature
{ {
/// <summary>
/// The base constructor of the <see cref="ScriptingProvider" /> class
/// </summary>
protected ScriptingProvider() protected ScriptingProvider()
{ {
Scripts = new(InternalScripts); Scripts = new ReadOnlyCollection<Script>(InternalScripts);
} }
/// <summary> /// <summary>

View File

@ -2,21 +2,28 @@
namespace Artemis.Core.Events namespace Artemis.Core.Events
{ {
/// <summary>
/// Represents an event argument containing a single value of type <typeparamref name="T" />
/// </summary>
/// <typeparam name="T">The type of value the argument contains</typeparam>
public class SingleValueEventArgs<T> : EventArgs public class SingleValueEventArgs<T> : EventArgs
{ {
#region Properties & Fields
public T Value { get; }
#endregion
#region Constructors #region Constructors
public SingleValueEventArgs(T value) internal SingleValueEventArgs(T value)
{ {
this.Value = value; Value = value;
} }
#endregion #endregion
#region Properties & Fields
/// <summary>
/// Gets the value of the argument
/// </summary>
public T Value { get; }
#endregion
} }
} }

View File

@ -3,42 +3,18 @@ using Newtonsoft.Json;
namespace Artemis.Core namespace Artemis.Core
{ {
/// <summary>
/// Represents an input pin containing a value of type <typeparamref name="T" /> on a <see cref="INode" />
/// </summary>
public sealed class InputPin<T> : Pin public sealed class InputPin<T> : Pin
{ {
#region Properties & Fields
public override Type Type { get; } = typeof(T);
public override object PinValue => Value;
public override PinDirection Direction => PinDirection.Input;
private T _value;
public T Value
{
get
{
if (!IsEvaluated)
Evaluate();
return _value;
}
private set
{
_value = value;
IsEvaluated = true;
OnPropertyChanged(nameof(PinValue));
}
}
#endregion
#region Constructors #region Constructors
[JsonConstructor] [JsonConstructor]
internal InputPin(INode node, string name) internal InputPin(INode node, string name)
: base(node, name) : base(node, name)
{ {
Value = default;
} }
#endregion #endregion
@ -47,25 +23,29 @@ namespace Artemis.Core
private void Evaluate() private void Evaluate()
{ {
if (ConnectedTo.Count > 0) if (ConnectedTo.Count > 0 && ConnectedTo[0].PinValue is T value)
if (ConnectedTo[0].PinValue is T value) Value = value;
Value = value;
} }
#endregion #endregion
}
public sealed class InputPin : Pin
{
#region Properties & Fields #region Properties & Fields
public override Type Type { get; } /// <inheritdoc />
public override object PinValue => Value; public override Type Type { get; } = typeof(T);
/// <inheritdoc />
public override object? PinValue => Value;
/// <inheritdoc />
public override PinDirection Direction => PinDirection.Input; public override PinDirection Direction => PinDirection.Input;
private object _value; private T? _value;
public object Value /// <summary>
/// Gets or sets the value of the input pin
/// </summary>
public T? Value
{ {
get get
{ {
@ -77,8 +57,6 @@ namespace Artemis.Core
private set private set
{ {
if (!Type.IsInstanceOfType(value)) throw new ArgumentException($"Value of type '{value?.GetType().Name ?? "null"}' can't be assigned to a pin of type {Type.Name}.");
_value = value; _value = value;
IsEvaluated = true; IsEvaluated = true;
OnPropertyChanged(nameof(PinValue)); OnPropertyChanged(nameof(PinValue));
@ -86,13 +64,20 @@ namespace Artemis.Core
} }
#endregion #endregion
}
/// <summary>
/// Represents an input pin on a <see cref="INode" />
/// </summary>
public sealed class InputPin : Pin
{
#region Constructors #region Constructors
internal InputPin(INode node, Type type, string name) internal InputPin(INode node, Type type, string name)
: base(node, name) : base(node, name)
{ {
this.Type = type; Type = type;
_value = type.GetDefault();
} }
#endregion #endregion
@ -115,5 +100,54 @@ namespace Artemis.Core
} }
#endregion #endregion
#region Properties & Fields
/// <inheritdoc />
public override Type Type { get; }
/// <inheritdoc />
public override object? PinValue => Value;
/// <inheritdoc />
public override PinDirection Direction => PinDirection.Input;
private object? _value;
/// <summary>
/// Gets or sets the value of the input pin
/// </summary>
public object? Value
{
get
{
if (!IsEvaluated)
Evaluate();
return _value;
}
private set
{
if (Type.IsValueType && value == null)
{
// We can't take null for value types so set it to the default value for that type
_value = Type.GetDefault();
}
else if (value != null)
{
// If a value was given make sure it matches
if (!Type.IsInstanceOfType(value))
throw new ArgumentException($"Value of type '{value.GetType().Name}' can't be assigned to a pin of type {Type.Name}.");
}
// Otherwise we're good and we can put a null here if it happens to be that
_value = value;
IsEvaluated = true;
OnPropertyChanged(nameof(PinValue));
}
}
#endregion
} }
} }

View File

@ -5,53 +5,63 @@ using System.Linq;
namespace Artemis.Core namespace Artemis.Core
{ {
/// <summary>
/// Represents a collection of input pins containing values of type <typeparamref name="T" />
/// </summary>
/// <typeparam name="T">The type of value the pins in this collection hold</typeparam>
public sealed class InputPinCollection<T> : PinCollection public sealed class InputPinCollection<T> : PinCollection
{ {
#region Properties & Fields
public override PinDirection Direction => PinDirection.Input;
public override Type Type => typeof(T);
public new IEnumerable<InputPin<T>> Pins => base.Pins.Cast<InputPin<T>>();
public IEnumerable<T> Values => Pins.Select(p => p.Value);
#endregion
#region Constructors #region Constructors
internal InputPinCollection(INode node, string name, int initialCount) internal InputPinCollection(INode node, string name, int initialCount)
: base(node, name, initialCount) : base(node, name, initialCount)
{ } {
}
#endregion #endregion
#region Methods #region Methods
protected override IPin CreatePin() => new InputPin<T>(Node, string.Empty); /// <inheritdoc />
protected override IPin CreatePin()
{
return new InputPin<T>(Node, string.Empty);
}
#endregion
#region Properties & Fields
/// <inheritdoc />
public override PinDirection Direction => PinDirection.Input;
/// <inheritdoc />
public override Type Type => typeof(T);
/// <summary>
/// Gets an enumerable of the pins in this collection
/// </summary>
public new IEnumerable<InputPin<T>> Pins => base.Pins.Cast<InputPin<T>>();
/// <summary>
/// Gets an enumerable of the values of the pins in this collection
/// </summary>
public IEnumerable<T> Values => Pins.Where(p => p.Value != null).Select(p => p.Value!);
#endregion #endregion
} }
/// <summary>
/// Represents a collection of input pins
/// </summary>
public sealed class InputPinCollection : PinCollection public sealed class InputPinCollection : PinCollection
{ {
#region Properties & Fields
public override PinDirection Direction => PinDirection.Input;
public override Type Type { get; }
public new IEnumerable<InputPin> Pins => base.Pins.Cast<InputPin>();
public IEnumerable Values => Pins.Select(p => p.Value);
#endregion
#region Constructors #region Constructors
internal InputPinCollection(INode node, Type type, string name, int initialCount) internal InputPinCollection(INode node, Type type, string name, int initialCount)
: base(node, name, 0) : base(node, name, 0)
{ {
this.Type = type; Type = type;
// Can't do this in the base constructor because the type won't be set yet // Can't do this in the base constructor because the type won't be set yet
for (int i = 0; i < initialCount; i++) for (int i = 0; i < initialCount; i++)
@ -62,8 +72,32 @@ namespace Artemis.Core
#region Methods #region Methods
protected override IPin CreatePin() => new InputPin(Node, Type, string.Empty); /// <inheritdoc />
protected override IPin CreatePin()
{
return new InputPin(Node, Type, string.Empty);
}
#endregion
#region Properties & Fields
/// <inheritdoc />
public override PinDirection Direction => PinDirection.Input;
/// <inheritdoc />
public override Type Type { get; }
/// <summary>
/// Gets an enumerable of the pins in this collection
/// </summary>
public new IEnumerable<InputPin> Pins => base.Pins.Cast<InputPin>();
/// <summary>
/// Gets an enumerable of the values of the pins in this collection
/// </summary>
public IEnumerable Values => Pins.Where(p => p.Value != null).Select(p => p.Value);
#endregion #endregion
} }
} }

View File

@ -65,7 +65,7 @@ namespace Artemis.Core
} }
/// <summary> /// <summary>
/// Represents a node script with a result value of type <paramref name="T" /> /// Represents a node script with a result value of type <typeparamref name="T" />
/// </summary> /// </summary>
/// <typeparam name="T">The type of result value</typeparam> /// <typeparam name="T">The type of result value</typeparam>
public interface INodeScript<out T> : INodeScript public interface INodeScript<out T> : INodeScript
@ -73,6 +73,6 @@ namespace Artemis.Core
/// <summary> /// <summary>
/// Gets the result of the script /// Gets the result of the script
/// </summary> /// </summary>
T Result { get; } T? Result { get; }
} }
} }

View File

@ -4,24 +4,76 @@ using Artemis.Core.Events;
namespace Artemis.Core namespace Artemis.Core
{ {
/// <summary>
/// Represents a pin containing a value on a <see cref="INode" />
/// </summary>
public interface IPin public interface IPin
{ {
/// <summary>
/// Gets the node the pin belongs to
/// </summary>
INode Node { get; } INode Node { get; }
/// <summary>
/// Gets or sets the name of the pin
/// </summary>
string Name { get; set; } string Name { get; set; }
PinDirection Direction { get; }
Type Type { get; }
object PinValue { get; }
/// <summary>
/// Gets the direction of the pin
/// </summary>
PinDirection Direction { get; }
/// <summary>
/// Gets the type of value the pin holds
/// </summary>
Type Type { get; }
/// <summary>
/// Gets the value the pin holds
/// </summary>
object? PinValue { get; }
/// <summary>
/// Gets a read only list of pins this pin is connected to
/// </summary>
IReadOnlyList<IPin> ConnectedTo { get; } IReadOnlyList<IPin> ConnectedTo { get; }
/// <summary>
/// Gets or sets a boolean indicating whether this pin is evaluated or not
/// </summary>
bool IsEvaluated { get; set; } bool IsEvaluated { get; set; }
/// <summary>
/// Occurs when the pin connects to another pin
/// </summary>
event EventHandler<SingleValueEventArgs<IPin>> PinConnected; event EventHandler<SingleValueEventArgs<IPin>> PinConnected;
/// <summary>
/// Occurs when the pin disconnects from another pin
/// </summary>
event EventHandler<SingleValueEventArgs<IPin>> PinDisconnected; event EventHandler<SingleValueEventArgs<IPin>> PinDisconnected;
/// <summary>
/// Resets the pin, causing it to re-evaluate the next time its value is requested
/// </summary>
void Reset();
/// <summary>
/// Connects the pin to the provided <paramref name="pin"></paramref>
/// </summary>
/// <param name="pin">The pin to connect this pin to</param>
void ConnectTo(IPin pin); void ConnectTo(IPin pin);
/// <summary>
/// Disconnects the pin to the provided <paramref name="pin"></paramref>
/// </summary>
/// <param name="pin">The pin to disconnect this pin to</param>
void DisconnectFrom(IPin pin); void DisconnectFrom(IPin pin);
/// <summary>
/// Disconnects all pins this pin is connected to
/// </summary>
void DisconnectAll(); void DisconnectAll();
} }
} }

View File

@ -4,16 +4,56 @@ using Artemis.Core.Events;
namespace Artemis.Core namespace Artemis.Core
{ {
/// <summary>
/// Represents a collection of <see cref="IPin" />s on a <see cref="INode" />
/// </summary>
public interface IPinCollection : IEnumerable<IPin> public interface IPinCollection : IEnumerable<IPin>
{ {
/// <summary>
/// Gets the node the pin collection belongs to
/// </summary>
INode Node { get; }
/// <summary>
/// Gets the name of the pin collection
/// </summary>
string Name { get; } string Name { get; }
/// <summary>
/// Gets the direction of the pin collection and all its pins
/// </summary>
PinDirection Direction { get; } PinDirection Direction { get; }
/// <summary>
/// Gets the type of values the pin collection and all its pins holds
/// </summary>
Type Type { get; } Type Type { get; }
/// <summary>
/// Occurs when a pin was added to the collection
/// </summary>
event EventHandler<SingleValueEventArgs<IPin>> PinAdded; event EventHandler<SingleValueEventArgs<IPin>> PinAdded;
/// <summary>
/// Occurs when a pin was removed from the collection
/// </summary>
event EventHandler<SingleValueEventArgs<IPin>> PinRemoved; event EventHandler<SingleValueEventArgs<IPin>> PinRemoved;
/// <summary>
/// Creates a new pin and adds it to the collection
/// </summary>
/// <returns>The newly added pin</returns>
IPin AddPin(); IPin AddPin();
/// <summary>
/// Removes the provided <paramref name="pin" /> from the collection
/// </summary>
/// <param name="pin">The pin to remove</param>
bool Remove(IPin pin); bool Remove(IPin pin);
/// <summary>
/// Resets the pin collection, causing its pins to re-evaluate the next time its value is requested
/// </summary>
void Reset();
} }
} }

View File

@ -27,7 +27,7 @@ namespace Artemis.Core.Internal
foreach (var (property, inputPin) in _propertyPins) foreach (var (property, inputPin) in _propertyPins)
{ {
if (inputPin.ConnectedTo.Any()) if (inputPin.ConnectedTo.Any())
_propertyValues[property] = inputPin.Value; _propertyValues[property] = inputPin.Value!;
else else
_propertyValues.Remove(property); _propertyValues.Remove(property);
} }
@ -55,7 +55,7 @@ namespace Artemis.Core.Internal
foreach (IDataBindingProperty property in DataBinding.Properties) foreach (IDataBindingProperty property in DataBinding.Properties)
_propertyPins.Add(property, CreateInputPin(property.ValueType, property.DisplayName)); _propertyPins.Add(property, CreateInputPin(property.ValueType, property.DisplayName));
} }
#region Event handlers #region Event handlers
private void DataBindingOnDataBindingPropertyRegistered(object? sender, DataBindingEventArgs e) private void DataBindingOnDataBindingPropertyRegistered(object? sender, DataBindingEventArgs e)

View File

@ -9,7 +9,7 @@
public InputPin<T> Input { get; } public InputPin<T> Input { get; }
public T Value { get; private set; } public T? Value { get; private set; }
public override bool IsExitNode => true; public override bool IsExitNode => true;

View File

@ -239,10 +239,14 @@ namespace Artemis.Core
/// <inheritdoc /> /// <inheritdoc />
public abstract void Evaluate(); public abstract void Evaluate();
/// <inheritdoc /> /// <inheritdoc />
public virtual void Reset() public virtual void Reset()
{ {
foreach (IPin pin in _pins)
pin.Reset();
foreach (IPinCollection pinCollection in _pinCollections)
pinCollection.Reset();
Resetting?.Invoke(this, EventArgs.Empty); Resetting?.Invoke(this, EventArgs.Empty);
} }

View File

@ -2,38 +2,69 @@
namespace Artemis.Core namespace Artemis.Core
{ {
/// <summary>
/// Represents an attribute that can be used to provide metadata on a node
/// </summary>
public class NodeAttribute : Attribute public class NodeAttribute : Attribute
{ {
#region Properties & Fields #region Properties & Fields
/// <summary>
/// Gets the name of the node
/// </summary>
public string Name { get; } public string Name { get; }
public string Description { get; set; }
public string Category { get; set; } /// <summary>
public Type InputType { get; set; } /// Gets the description of the node
public Type OutputType { get; set; } /// </summary>
public string Description { get; } = string.Empty;
/// <summary>
/// Gets the category of the node
/// </summary>
public string Category { get; } = string.Empty;
/// <summary>
/// Gets the primary input type of the node
/// </summary>
public Type? InputType { get; init; }
/// <summary>
/// Gets the primary output type of the node
/// </summary>
public Type? OutputType { get; init; }
#endregion #endregion
#region Constructors #region Constructors
/// <summary>
/// Creates a new instance of the <see cref="NodeAttribute" /> class
/// </summary>
public NodeAttribute(string name) public NodeAttribute(string name)
{ {
this.Name = name; Name = name;
} }
/// <summary>
/// Creates a new instance of the <see cref="NodeAttribute" /> class
/// </summary>
public NodeAttribute(string name, string description) public NodeAttribute(string name, string description)
{ {
this.Name = name; Name = name;
this.Description = description; Description = description;
} }
/// <summary>
/// Creates a new instance of the <see cref="NodeAttribute" /> class
/// </summary>
public NodeAttribute(string name, string description, string category) public NodeAttribute(string name, string description, string category)
{ {
this.Name = name; Name = name;
this.Description = description; Description = description;
this.Category = category; Category = category;
} }
#endregion #endregion
} }
} }

View File

@ -3,43 +3,81 @@ using Artemis.Storage.Entities.Profile.Nodes;
namespace Artemis.Core namespace Artemis.Core
{ {
/// <summary>
/// Represents node data describing a certain <see cref="INode" />
/// </summary>
public class NodeData public class NodeData
{ {
#region Properties & Fields
public Plugin Plugin { get; }
public Type Type { get; }
public string Name { get; }
public string Description { get; }
public string Category { get; }
public Type? InputType { get; }
public Type? OutputType { get; }
private Func<INodeScript, NodeEntity?, INode> _create;
#endregion
#region Constructors #region Constructors
internal NodeData(Plugin plugin, Type type, string name, string description, string category, Type? inputType, Type? outputType, Func<INodeScript, NodeEntity?, INode>? create) internal NodeData(Plugin plugin, Type type, string name, string description, string category, Type? inputType, Type? outputType, Func<INodeScript, NodeEntity?, INode> create)
{ {
this.Plugin = plugin; Plugin = plugin;
this.Type = type; Type = type;
this.Name = name; Name = name;
this.Description = description; Description = description;
this.Category = category; Category = category;
this.InputType = inputType; InputType = inputType;
this.OutputType = outputType; OutputType = outputType;
this._create = create; _create = create;
} }
#endregion #endregion
#region Methods #region Methods
public INode CreateNode(INodeScript script, NodeEntity? entity) => _create(script, entity); /// <summary>
/// Creates a new instance of the node this data represents
/// </summary>
/// <param name="script">The script to create the node for</param>
/// <param name="entity">An optional storage entity to apply to the node</param>
/// <returns>The returning node of type <see cref="Type" /></returns>
public INode CreateNode(INodeScript script, NodeEntity? entity)
{
return _create(script, entity);
}
#endregion
#region Properties & Fields
/// <summary>
/// Gets the plugin that provided this node data
/// </summary>
public Plugin Plugin { get; }
/// <summary>
/// Gets the type of <see cref="INode" /> this data represents
/// </summary>
public Type Type { get; }
/// <summary>
/// Gets the name of the node this data represents
/// </summary>
public string Name { get; }
/// <summary>
/// Gets the description of the node this data represents
/// </summary>
public string Description { get; }
/// <summary>
/// Gets the category of the node this data represents
/// </summary>
public string Category { get; }
/// <summary>
/// Gets the primary input type of the node this data represents
/// </summary>
public Type? InputType { get; }
/// <summary>
/// Gets the primary output of the node this data represents
/// </summary>
public Type? OutputType { get; }
private readonly Func<INodeScript, NodeEntity?, INode> _create;
#endregion #endregion
} }
} }

View File

@ -60,12 +60,19 @@ namespace Artemis.Core
#region Constructors #region Constructors
public NodeScript(string name, string description, object? context = null) /// <summary>
/// Creates a new instance of the <see cref="NodeScript"/> class with a name, description and optional context
/// </summary>
/// <param name="name">The name of the node script</param>
/// <param name="description">The description of the node script</param>
/// <param name="context">The context of the node script, usually a <see cref="Profile" /> or <see cref="ProfileConfiguration" /></param>
protected NodeScript(string name, string description, object? context = null)
{ {
Name = name; Name = name;
Description = description; Description = description;
Context = context; Context = context;
Entity = new NodeScriptEntity(); Entity = new NodeScriptEntity();
ExitNode = null!;
NodeTypeStore.NodeTypeAdded += NodeTypeStoreOnNodeTypeChanged; NodeTypeStore.NodeTypeAdded += NodeTypeStoreOnNodeTypeChanged;
NodeTypeStore.NodeTypeRemoved += NodeTypeStoreOnNodeTypeChanged; NodeTypeStore.NodeTypeRemoved += NodeTypeStoreOnNodeTypeChanged;
@ -77,6 +84,7 @@ namespace Artemis.Core
Description = description; Description = description;
Entity = entity; Entity = entity;
Context = context; Context = context;
ExitNode = null!;
NodeTypeStore.NodeTypeAdded += NodeTypeStoreOnNodeTypeChanged; NodeTypeStore.NodeTypeAdded += NodeTypeStoreOnNodeTypeChanged;
NodeTypeStore.NodeTypeRemoved += NodeTypeStoreOnNodeTypeChanged; NodeTypeStore.NodeTypeRemoved += NodeTypeStoreOnNodeTypeChanged;
@ -176,6 +184,8 @@ namespace Artemis.Core
if (collection == null) if (collection == null)
continue; continue;
while (collection.Count() > entityNodePinCollection.Amount)
collection.Remove(collection.Last());
while (collection.Count() < entityNodePinCollection.Amount) while (collection.Count() < entityNodePinCollection.Amount)
collection.AddPin(); collection.AddPin();
} }
@ -333,7 +343,7 @@ namespace Artemis.Core
} }
/// <summary> /// <summary>
/// Represents a node script with a result value of type <paramref name="T" /> /// Represents a node script with a result value of type <typeparamref name="T" />
/// </summary> /// </summary>
/// <typeparam name="T">The type of result value</typeparam> /// <typeparam name="T">The type of result value</typeparam>
public class NodeScript<T> : NodeScript, INodeScript<T> public class NodeScript<T> : NodeScript, INodeScript<T>
@ -341,7 +351,7 @@ namespace Artemis.Core
#region Properties & Fields #region Properties & Fields
/// <inheritdoc /> /// <inheritdoc />
public T Result => ((ExitNode<T>) ExitNode).Value; public T? Result => ((ExitNode<T>) ExitNode).Value;
/// <inheritdoc /> /// <inheritdoc />
public override bool ExitNodeConnected => ((ExitNode<T>) ExitNode).Input.ConnectedTo.Any(); public override bool ExitNodeConnected => ((ExitNode<T>) ExitNode).Input.ConnectedTo.Any();
@ -362,6 +372,7 @@ namespace Artemis.Core
Load(); Load();
} }
/// <inheritdoc />
public NodeScript(string name, string description, object? context = null) public NodeScript(string name, string description, object? context = null)
: base(name, description, context) : base(name, description, context)
{ {

View File

@ -3,55 +3,39 @@ using Newtonsoft.Json;
namespace Artemis.Core namespace Artemis.Core
{ {
/// <summary>
/// Represents an output pin containing a value of type <typeparamref name="T" /> on a <see cref="INode" />
/// </summary>
public sealed class OutputPin<T> : Pin public sealed class OutputPin<T> : Pin
{ {
#region Properties & Fields
public override Type Type { get; } = typeof(T);
public override object PinValue => Value;
public override PinDirection Direction => PinDirection.Output;
private T _value;
public T Value
{
get
{
if (!IsEvaluated)
Node?.Evaluate();
return _value;
}
set
{
_value = value;
IsEvaluated = true;
OnPropertyChanged(nameof(PinValue));
}
}
#endregion
#region Constructors #region Constructors
[JsonConstructor] [JsonConstructor]
internal OutputPin(INode node, string name) internal OutputPin(INode node, string name)
: base(node, name) : base(node, name)
{ } {
_value = default;
}
#endregion #endregion
}
public sealed class OutputPin : Pin
{
#region Properties & Fields #region Properties & Fields
public override Type Type { get; } /// <inheritdoc />
public override object PinValue => Value; public override Type Type { get; } = typeof(T);
/// <inheritdoc />
public override object? PinValue => Value;
/// <inheritdoc />
public override PinDirection Direction => PinDirection.Output; public override PinDirection Direction => PinDirection.Output;
private object _value; private T? _value;
public object Value
/// <summary>
/// Gets or sets the value of the output pin
/// </summary>
public T? Value
{ {
get get
{ {
@ -62,8 +46,72 @@ namespace Artemis.Core
} }
set set
{ {
if (!Type.IsInstanceOfType(value)) throw new ArgumentException($"Value of type '{value?.GetType().Name ?? "null"}' can't be assigned to a pin of type {Type.Name}."); _value = value;
IsEvaluated = true;
OnPropertyChanged(nameof(PinValue));
}
}
#endregion
}
/// <summary>
/// Represents an output pin on a <see cref="INode" />
/// </summary>
public sealed class OutputPin : Pin
{
#region Constructors
internal OutputPin(INode node, Type type, string name)
: base(node, name)
{
Type = type;
_value = type.GetDefault();
}
#endregion
#region Properties & Fields
/// <inheritdoc />
public override Type Type { get; }
/// <inheritdoc />
public override object? PinValue => Value;
/// <inheritdoc />
public override PinDirection Direction => PinDirection.Output;
private object? _value;
/// <summary>
/// Gets or sets the value of the output pin
/// </summary>
public object? Value
{
get
{
if (!IsEvaluated)
Node?.Evaluate();
return _value;
}
set
{
if (Type.IsValueType && value == null)
{
// We can't take null for value types so set it to the default value for that type
_value = Type.GetDefault();
}
else if (value != null)
{
// If a value was given make sure it matches
if (!Type.IsInstanceOfType(value))
throw new ArgumentException($"Value of type '{value.GetType().Name}' can't be assigned to a pin of type {Type.Name}.");
}
// Otherwise we're good and we can put a null here if it happens to be that
_value = value; _value = value;
IsEvaluated = true; IsEvaluated = true;
OnPropertyChanged(nameof(PinValue)); OnPropertyChanged(nameof(PinValue));
@ -71,15 +119,5 @@ namespace Artemis.Core
} }
#endregion #endregion
#region Constructors
internal OutputPin(INode node, Type type, string name)
: base(node, name)
{
this.Type = type;
}
#endregion
} }
} }

View File

@ -2,11 +2,17 @@
namespace Artemis.Core namespace Artemis.Core
{ {
/// <summary>
/// Represents a collection of output pins containing values of type <typeparamref name="T" />
/// </summary>
/// <typeparam name="T">The type of value the pins in this collection hold</typeparam>
public sealed class OutputPinCollection<T> : PinCollection public sealed class OutputPinCollection<T> : PinCollection
{ {
#region Properties & Fields #region Properties & Fields
/// <inheritdoc />
public override PinDirection Direction => PinDirection.Output; public override PinDirection Direction => PinDirection.Output;
/// <inheritdoc />
public override Type Type => typeof(T); public override Type Type => typeof(T);
#endregion #endregion
@ -21,6 +27,7 @@ namespace Artemis.Core
#region Methods #region Methods
/// <inheritdoc />
protected override IPin CreatePin() => new OutputPin<T>(Node, string.Empty); protected override IPin CreatePin() => new OutputPin<T>(Node, string.Empty);
#endregion #endregion

View File

@ -5,12 +5,35 @@ using Artemis.Core.Events;
namespace Artemis.Core namespace Artemis.Core
{ {
/// <inheritdoc cref="IPin" />
public abstract class Pin : CorePropertyChanged, IPin public abstract class Pin : CorePropertyChanged, IPin
{ {
#region Constructors
/// <summary>
/// Creates a new instance of the <see cref="Pin" /> class on the provided node with the provided name
/// </summary>
/// <param name="node">The node the pin belongs to</param>
/// <param name="name">The name of the pin</param>
protected Pin(INode node, string name = "")
{
Node = node;
_name = name;
}
#endregion
/// <inheritdoc />
public event EventHandler<SingleValueEventArgs<IPin>>? PinConnected;
/// <inheritdoc />
public event EventHandler<SingleValueEventArgs<IPin>>? PinDisconnected;
#region Properties & Fields #region Properties & Fields
/// <inheritdoc />
public INode Node { get; } public INode Node { get; }
/// <inheritdoc />
public string Name public string Name
{ {
get => _name; get => _name;
@ -19,6 +42,7 @@ namespace Artemis.Core
private bool _isEvaluated; private bool _isEvaluated;
/// <inheritdoc />
public bool IsEvaluated public bool IsEvaluated
{ {
get => _isEvaluated; get => _isEvaluated;
@ -27,36 +51,30 @@ namespace Artemis.Core
private readonly List<IPin> _connectedTo = new(); private readonly List<IPin> _connectedTo = new();
private string _name; private string _name;
/// <inheritdoc />
public IReadOnlyList<IPin> ConnectedTo => new ReadOnlyCollection<IPin>(_connectedTo); public IReadOnlyList<IPin> ConnectedTo => new ReadOnlyCollection<IPin>(_connectedTo);
/// <inheritdoc />
public abstract PinDirection Direction { get; } public abstract PinDirection Direction { get; }
/// <inheritdoc />
public abstract Type Type { get; } public abstract Type Type { get; }
public abstract object PinValue { get; }
#endregion /// <inheritdoc />
public abstract object? PinValue { get; }
#region Events
public event EventHandler<SingleValueEventArgs<IPin>> PinConnected;
public event EventHandler<SingleValueEventArgs<IPin>> PinDisconnected;
#endregion
#region Constructors
protected Pin(INode node, string name = "")
{
this.Node = node;
this.Name = name;
if (Node != null)
Node.Resetting += OnNodeResetting;
}
#endregion #endregion
#region Methods #region Methods
/// <inheritdoc />
public void Reset()
{
IsEvaluated = false;
}
/// <inheritdoc />
public void ConnectTo(IPin pin) public void ConnectTo(IPin pin)
{ {
_connectedTo.Add(pin); _connectedTo.Add(pin);
@ -65,6 +83,7 @@ namespace Artemis.Core
PinConnected?.Invoke(this, new SingleValueEventArgs<IPin>(pin)); PinConnected?.Invoke(this, new SingleValueEventArgs<IPin>(pin));
} }
/// <inheritdoc />
public void DisconnectFrom(IPin pin) public void DisconnectFrom(IPin pin)
{ {
_connectedTo.Remove(pin); _connectedTo.Remove(pin);
@ -73,6 +92,7 @@ namespace Artemis.Core
PinDisconnected?.Invoke(this, new SingleValueEventArgs<IPin>(pin)); PinDisconnected?.Invoke(this, new SingleValueEventArgs<IPin>(pin));
} }
/// <inheritdoc />
public void DisconnectAll() public void DisconnectAll()
{ {
List<IPin> connectedPins = new(_connectedTo); List<IPin> connectedPins = new(_connectedTo);
@ -84,11 +104,6 @@ namespace Artemis.Core
PinDisconnected?.Invoke(this, new SingleValueEventArgs<IPin>(pin)); PinDisconnected?.Invoke(this, new SingleValueEventArgs<IPin>(pin));
} }
private void OnNodeResetting(object sender, EventArgs e)
{
IsEvaluated = false;
}
#endregion #endregion
} }
} }

View File

@ -6,34 +6,22 @@ using Artemis.Core.Events;
namespace Artemis.Core namespace Artemis.Core
{ {
/// <inheritdoc cref="IPinCollection"/>
public abstract class PinCollection : IPinCollection public abstract class PinCollection : IPinCollection
{ {
#region Properties & Fields
public INode Node { get; }
public string Name { get; }
public abstract PinDirection Direction { get; }
public abstract Type Type { get; }
private readonly ObservableCollection<IPin> _pins = new();
public ReadOnlyObservableCollection<IPin> Pins => new(_pins);
#endregion
#region Events
public event EventHandler<SingleValueEventArgs<IPin>> PinAdded;
public event EventHandler<SingleValueEventArgs<IPin>> PinRemoved;
#endregion
#region Constructors #region Constructors
/// <summary>
/// Creates a new instance of the <see cref="PinCollection" /> class
/// </summary>
/// <param name="node">The node the pin collection belongs to</param>
/// <param name="name">The name of the pin collection</param>
/// <param name="initialCount">The amount of pins to initially add to the collection</param>
/// <returns>The resulting output pin collection</returns>
protected PinCollection(INode node, string name, int initialCount) protected PinCollection(INode node, string name, int initialCount)
{ {
this.Node = node; Node = node ?? throw new ArgumentNullException(nameof(node));
this.Name = name; Name = name;
for (int i = 0; i < initialCount; i++) for (int i = 0; i < initialCount; i++)
AddPin(); AddPin();
@ -41,9 +29,38 @@ namespace Artemis.Core
#endregion #endregion
/// <inheritdoc />
public event EventHandler<SingleValueEventArgs<IPin>>? PinAdded;
/// <inheritdoc />
public event EventHandler<SingleValueEventArgs<IPin>>? PinRemoved;
#region Properties & Fields
/// <inheritdoc />
public INode Node { get; }
/// <inheritdoc />
public string Name { get; }
/// <inheritdoc />
public abstract PinDirection Direction { get; }
/// <inheritdoc />
public abstract Type Type { get; }
private readonly ObservableCollection<IPin> _pins = new();
/// <summary>
/// Gets a read only observable collection of the pins
/// </summary>
public ReadOnlyObservableCollection<IPin> Pins => new(_pins);
#endregion
#region Methods #region Methods
/// <inheritdoc />
public IPin AddPin() public IPin AddPin()
{ {
IPin pin = CreatePin(); IPin pin = CreatePin();
@ -54,6 +71,7 @@ namespace Artemis.Core
return pin; return pin;
} }
/// <inheritdoc />
public bool Remove(IPin pin) public bool Remove(IPin pin)
{ {
bool removed = _pins.Remove(pin); bool removed = _pins.Remove(pin);
@ -64,11 +82,30 @@ namespace Artemis.Core
return removed; return removed;
} }
/// <inheritdoc />
public void Reset()
{
foreach (IPin pin in _pins)
pin.Reset();
}
/// <summary>
/// Creates a new pin to be used in this collection
/// </summary>
/// <returns>The resulting pin</returns>
protected abstract IPin CreatePin(); protected abstract IPin CreatePin();
public IEnumerator<IPin> GetEnumerator() => Pins.GetEnumerator(); /// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator<IPin> GetEnumerator()
{
return Pins.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion #endregion
} }
} }

View File

@ -1,8 +1,18 @@
namespace Artemis.Core namespace Artemis.Core
{ {
/// <summary>
/// Represents a direction in which pin data flows
/// </summary>
public enum PinDirection public enum PinDirection
{ {
/// <summary>
/// An input direction
/// </summary>
Input, Input,
/// <summary>
/// An output direction
/// </summary>
Output Output
} }
} }

View File

@ -63,7 +63,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
} }
} }
private void DataBindingOnDataBindingToggled(object? sender, DataBindingEventArgs e) private void DataBindingOnDataBindingToggled(object sender, DataBindingEventArgs e)
{ {
OnPropertyChanged(nameof(DataBindingEnabled)); OnPropertyChanged(nameof(DataBindingEnabled));
} }

View File

@ -22,8 +22,7 @@ namespace Artemis.UI.Stylet
{ {
base.Dispose(); base.Dispose();
ScreenExtensions.TryDispose(_rootViewModel); ScreenExtensions.TryDispose(_rootViewModel);
if (Kernel != null) Kernel?.Dispose();
Kernel.Dispose();
} }
protected override void ConfigureBootstrapper() protected override void ConfigureBootstrapper()

View File

@ -277,7 +277,7 @@ namespace Artemis.VisualScripting.Editor.Controls
FitScript(); FitScript();
} }
private void OnVisualScriptNodeCollectionChanged(object? sender, EventArgs e) private void OnVisualScriptNodeCollectionChanged(object sender, EventArgs e)
{ {
if (AutoFitScript) if (AutoFitScript)
FitScript(); FitScript();

View File

@ -24,7 +24,7 @@
<Setter Property="Template"> <Setter Property="Template">
<Setter.Value> <Setter.Value>
<ControlTemplate TargetType="Button"> <ControlTemplate TargetType="Button">
<Border Padding="{TemplateBinding Padding}" <Border Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}" Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}" BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"> BorderBrush="{TemplateBinding BorderBrush}">
@ -103,19 +103,18 @@
<Setter Property="ItemTemplate"> <Setter Property="ItemTemplate">
<Setter.Value> <Setter.Value>
<DataTemplate DataType="{x:Type wrapper:VisualScriptPinCollection}"> <DataTemplate DataType="{x:Type wrapper:VisualScriptPinCollection}">
<StackPanel Margin="0,4" Orientation="Vertical"> <StackPanel Margin="0,2" Orientation="Vertical">
<TextBlock Text="{Binding PinCollection.Name}" Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type controls:VisualScriptNodePresenter}}}" /> <TextBlock Text="{Binding PinCollection.Name}" Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type controls:VisualScriptNodePresenter}}}" />
<ItemsControl Margin="0,4" <ItemsControl Margin="0,5"
Style="{StaticResource StylePinListInput}" Style="{StaticResource StylePinListInput}"
ItemsSource="{Binding Pins}"> ItemsSource="{Binding Pins}">
<ItemsControl.ItemTemplate> <ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type core:Pin}"> <DataTemplate DataType="{x:Type core:Pin}">
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal"> <StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Margin="0 8 0 0">
<controls:VisualScriptPinPresenter Margin="0,5,-3,3" <controls:VisualScriptPinPresenter Pin="{Binding .}" Margin="0 0 2 0" />
Pin="{Binding .}" />
<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}}}"
CommandParameter="{Binding .}"/> CommandParameter="{Binding .}" />
</StackPanel> </StackPanel>
</DataTemplate> </DataTemplate>
</ItemsControl.ItemTemplate> </ItemsControl.ItemTemplate>
@ -139,14 +138,14 @@
<StackPanel Margin="0,4" Orientation="Vertical"> <StackPanel Margin="0,4" Orientation="Vertical">
<TextBlock Text="{Binding PinCollection.Name}" Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type controls:VisualScriptNodePresenter}}}" /> <TextBlock Text="{Binding PinCollection.Name}" Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type controls:VisualScriptNodePresenter}}}" />
<ItemsControl Margin="0,4" <ItemsControl Margin="0,4"
Style="{StaticResource StylePinListOutput}" Style="{StaticResource StylePinListOutput}"
ItemsSource="{Binding Pins}"> ItemsSource="{Binding Pins}">
<ItemsControl.ItemTemplate> <ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type core: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}}}"
CommandParameter="{Binding .}"/> CommandParameter="{Binding .}" />
<controls:VisualScriptPinPresenter Margin="-3,5,0,3" <controls:VisualScriptPinPresenter Margin="-3,5,0,3"
Pin="{Binding .}" /> Pin="{Binding .}" />
</StackPanel> </StackPanel>
@ -182,9 +181,9 @@
<!-- Placeholder --> <!-- Placeholder -->
</Border> </Border>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center"
FontFamily="{TemplateBinding FontFamily}" FontFamily="{TemplateBinding FontFamily}"
FontSize="14" FontWeight="Bold" FontSize="14" FontWeight="Bold"
Text="{Binding Node.Node.Name, RelativeSource={RelativeSource TemplatedParent}}"/> Text="{Binding Node.Node.Name, RelativeSource={RelativeSource TemplatedParent}}" />
</DockPanel> </DockPanel>
</Border> </Border>
@ -199,24 +198,24 @@
<Border x:Name="BrdInputPins" Grid.Column="0"> <Border x:Name="BrdInputPins" Grid.Column="0">
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<ItemsControl Style="{StaticResource StylePinListInput}" <ItemsControl Style="{StaticResource StylePinListInput}"
ItemsSource="{Binding Node.InputPins, RelativeSource={RelativeSource TemplatedParent}}" /> ItemsSource="{Binding Node.InputPins, RelativeSource={RelativeSource TemplatedParent}}" />
<ItemsControl Style="{StaticResource StylePinCollectionListInput}" <ItemsControl Style="{StaticResource StylePinCollectionListInput}"
ItemsSource="{Binding Node.InputPinCollections, RelativeSource={RelativeSource TemplatedParent}}" /> ItemsSource="{Binding Node.InputPinCollections, RelativeSource={RelativeSource TemplatedParent}}" />
</StackPanel> </StackPanel>
</Border> </Border>
<Border x:Name="BrdCustomView" Grid.Column="1"> <Border x:Name="BrdCustomView" Grid.Column="1">
<ContentControl s:View.Model="{TemplateBinding CustomViewModel}"/> <ContentControl s:View.Model="{TemplateBinding CustomViewModel}" />
</Border> </Border>
<Border x:Name="BrdOutputPins" Grid.Column="2"> <Border x:Name="BrdOutputPins" Grid.Column="2">
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<ItemsControl Style="{StaticResource StylePinListOutput}" <ItemsControl Style="{StaticResource StylePinListOutput}"
ItemsSource="{Binding Node.OutputPins, RelativeSource={RelativeSource TemplatedParent}}" /> ItemsSource="{Binding Node.OutputPins, RelativeSource={RelativeSource TemplatedParent}}" />
<ItemsControl Style="{StaticResource StylePinCollectionListOutput}" <ItemsControl Style="{StaticResource StylePinCollectionListOutput}"
ItemsSource="{Binding Node.OutputPinCollections, RelativeSource={RelativeSource TemplatedParent}}" /> ItemsSource="{Binding Node.OutputPinCollections, RelativeSource={RelativeSource TemplatedParent}}" />
</StackPanel> </StackPanel>
</Border> </Border>
@ -226,12 +225,12 @@
</Border> </Border>
</ControlTemplate> </ControlTemplate>
<Style x:Key="StyleVisualScriptNodePresenter" <Style x:Key="StyleVisualScriptNodePresenter"
TargetType="{x:Type controls:VisualScriptNodePresenter}"> TargetType="{x:Type controls:VisualScriptNodePresenter}">
<Setter Property="Padding" Value="8,10" /> <Setter Property="Padding" Value="8,10" />
<Setter Property="Foreground" Value="#FFFFFFFF"/> <Setter Property="Foreground" Value="#FFFFFFFF" />
<Setter Property="Background" Value="#80101010" /> <Setter Property="Background" Value="#80101010" />
<Setter Property="TitleBrush" Value="#FF444444" /> <Setter Property="TitleBrush" Value="#FF444444" />

View File

@ -110,7 +110,7 @@ namespace Artemis.VisualScripting.Nodes
CreateOutputPin(dataBindingRegistration.ValueType, dataBindingRegistration.DisplayName); CreateOutputPin(dataBindingRegistration.ValueType, dataBindingRegistration.DisplayName);
} }
private void ProfileOnChildRemoved(object? sender, EventArgs e) private void ProfileOnChildRemoved(object sender, EventArgs e)
{ {
if (Script.Context is not Profile profile) if (Script.Context is not Profile profile)
return; return;

View File

@ -8,7 +8,7 @@ using NoStringEvaluating.Models.Values;
namespace Artemis.VisualScripting.Nodes.Maths namespace Artemis.VisualScripting.Nodes.Maths
{ {
[Node("Math Expression", "Outputs the result of a math expression.", "Math", OutputType = typeof(int))] [Node("Math Expression", "Outputs the result of a math expression.", "Math", InputType = typeof(float), OutputType = typeof(float))]
public class MathExpressionNode : Node<string, MathExpressionNodeCustomViewModel> public class MathExpressionNode : Node<string, MathExpressionNodeCustomViewModel>
{ {
private readonly INoStringEvaluator _evaluator; private readonly INoStringEvaluator _evaluator;
@ -42,6 +42,7 @@ namespace Artemis.VisualScripting.Nodes.Maths
public override void Evaluate() public override void Evaluate()
{ {
var test = _evaluator.ToString();
if (Storage != null) if (Storage != null)
Output.Value = (float) _evaluator.CalcNumber(Storage, _variables); Output.Value = (float) _evaluator.CalcNumber(Storage, _variables);
} }