diff --git a/src/Artemis.Core/Utilities/Numeric.cs b/src/Artemis.Core/Utilities/Numeric.cs
index ac779d557..d96516148 100644
--- a/src/Artemis.Core/Utilities/Numeric.cs
+++ b/src/Artemis.Core/Utilities/Numeric.cs
@@ -257,7 +257,7 @@ namespace Artemis.Core
///
/// Returns a boolean indicating whether the provided type can be used as a .
///
- public static bool IsTypeCompatible(Type type)
+ public static bool IsTypeCompatible(Type? type)
{
return type == typeof(Numeric) ||
type == typeof(float) ||
diff --git a/src/Artemis.Core/VisualScripting/InputPin.cs b/src/Artemis.Core/VisualScripting/InputPin.cs
index 2d2320962..2b218fb44 100644
--- a/src/Artemis.Core/VisualScripting/InputPin.cs
+++ b/src/Artemis.Core/VisualScripting/InputPin.cs
@@ -1,4 +1,6 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
using Newtonsoft.Json;
namespace Artemis.Core
@@ -76,7 +78,7 @@ namespace Artemis.Core
internal InputPin(INode node, Type type, string name)
: base(node, name)
{
- Type = type;
+ _type = type;
_value = type.GetDefault();
}
@@ -84,6 +86,25 @@ namespace Artemis.Core
#region Methods
+ ///
+ /// Changes the type of this pin, disconnecting any pins that are incompatible with the new type.
+ ///
+ /// The new type of the pin.
+ public void ChangeType(Type type)
+ {
+ if (_type == type)
+ return;
+
+ // Disconnect pins incompatible with the new type
+ List toDisconnect = ConnectedTo.Where(p => !p.IsTypeCompatible(type)).ToList();
+ foreach (IPin pin in toDisconnect)
+ DisconnectFrom(pin);
+
+ // Change the type
+ SetAndNotify(ref _type, type, nameof(Type));
+ Value = type.GetDefault();
+ }
+
private void Evaluate()
{
if (Type.IsValueType)
@@ -104,7 +125,7 @@ namespace Artemis.Core
#region Properties & Fields
///
- public override Type Type { get; }
+ public override Type Type => _type;
///
public override object? PinValue => Value;
@@ -113,6 +134,7 @@ namespace Artemis.Core
public override PinDirection Direction => PinDirection.Input;
private object? _value;
+ private Type _type;
///
/// Gets or sets the value of the input pin
diff --git a/src/Artemis.Core/VisualScripting/InputPinCollection.cs b/src/Artemis.Core/VisualScripting/InputPinCollection.cs
index fd4da2bf0..9c2afde00 100644
--- a/src/Artemis.Core/VisualScripting/InputPinCollection.cs
+++ b/src/Artemis.Core/VisualScripting/InputPinCollection.cs
@@ -59,12 +59,14 @@ namespace Artemis.Core
///
public sealed class InputPinCollection : PinCollection
{
+ private Type _type;
+
#region Constructors
internal InputPinCollection(INode node, Type type, string name, int initialCount)
: base(node, name)
{
- Type = type;
+ _type = type;
// Can't do this in the base constructor because the type won't be set yet
for (int i = 0; i < initialCount; i++)
@@ -75,6 +77,20 @@ namespace Artemis.Core
#region Methods
+ ///
+ /// Changes the type of this pin, disconnecting any pins that are incompatible with the new type.
+ ///
+ /// The new type of the pin.
+ public void ChangeType(Type type)
+ {
+ if (_type == type)
+ return;
+
+ foreach (IPin pin in Pins)
+ (pin as InputPin)?.ChangeType(type);
+ SetAndNotify(ref _type, type, nameof(Type));
+ }
+
///
public override IPin CreatePin()
{
@@ -89,17 +105,12 @@ namespace Artemis.Core
public override PinDirection Direction => PinDirection.Input;
///
- public override Type Type { get; }
-
- ///
- /// Gets an enumerable of the pins in this collection
- ///
- public new IEnumerable Pins => base.Pins.Cast();
+ public override Type Type => _type;
///
/// Gets an enumerable of the values of the pins in this collection
///
- public IEnumerable Values => Pins.Where(p => p.Value != null).Select(p => p.Value);
+ public IEnumerable Values => Pins.Where(p => p.PinValue != null).Select(p => p.PinValue);
#endregion
}
diff --git a/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs b/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs
index 22afe5f48..197f40365 100644
--- a/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs
+++ b/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs
@@ -75,5 +75,12 @@ namespace Artemis.Core
/// Disconnects all pins this pin is connected to
///
void DisconnectAll();
+
+ ///
+ /// Determines whether this pin is compatible with the given type
+ ///
+ /// The type to check for compatibility
+ /// if the type is compatible, otherwise .
+ public bool IsTypeCompatible(Type type);
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/VisualScripting/OutputPin.cs b/src/Artemis.Core/VisualScripting/OutputPin.cs
index e7dc10bd5..a2b1ce1f0 100644
--- a/src/Artemis.Core/VisualScripting/OutputPin.cs
+++ b/src/Artemis.Core/VisualScripting/OutputPin.cs
@@ -1,4 +1,6 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
using Newtonsoft.Json;
namespace Artemis.Core
@@ -66,16 +68,36 @@ namespace Artemis.Core
internal OutputPin(INode node, Type type, string name)
: base(node, name)
{
- Type = type;
+ _type = type;
_value = type.GetDefault();
}
#endregion
+ #region Methods
+
+ ///
+ /// Changes the type of this pin, disconnecting any pins that are incompatible with the new type.
+ ///
+ /// The new type of the pin.
+ public void ChangeType(Type type)
+ {
+ // Disconnect pins incompatible with the new type
+ List toDisconnect = ConnectedTo.Where(p => !p.IsTypeCompatible(type)).ToList();
+ foreach (IPin pin in toDisconnect)
+ DisconnectFrom(pin);
+
+ // Change the type
+ SetAndNotify(ref _type, type, nameof(Type));
+ Value = type.GetDefault();
+ }
+
+ #endregion
+
#region Properties & Fields
///
- public override Type Type { get; }
+ public override Type Type => _type;
///
public override object? PinValue => Value;
@@ -84,6 +106,7 @@ namespace Artemis.Core
public override PinDirection Direction => PinDirection.Output;
private object? _value;
+ private Type _type;
///
/// Gets or sets the value of the output pin
diff --git a/src/Artemis.Core/VisualScripting/Pin.cs b/src/Artemis.Core/VisualScripting/Pin.cs
index 0d48693af..46916fae5 100644
--- a/src/Artemis.Core/VisualScripting/Pin.cs
+++ b/src/Artemis.Core/VisualScripting/Pin.cs
@@ -101,6 +101,9 @@ namespace Artemis.Core
///
public void DisconnectAll()
{
+ if (!_connectedTo.Any())
+ return;
+
List connectedPins = new(_connectedTo);
_connectedTo.Clear();
@@ -114,6 +117,12 @@ namespace Artemis.Core
OnPropertyChanged(nameof(ConnectedTo));
}
+ ///
+ public bool IsTypeCompatible(Type type) => Type == type
+ || Type == typeof(Enum) && type.IsEnum
+ || Direction == PinDirection.Input && Type == typeof(object)
+ || Direction == PinDirection.Output && type == typeof(object);
+
#endregion
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/VisualScripting/PinCollection.cs b/src/Artemis.Core/VisualScripting/PinCollection.cs
index 5c060d884..fd04d57f8 100644
--- a/src/Artemis.Core/VisualScripting/PinCollection.cs
+++ b/src/Artemis.Core/VisualScripting/PinCollection.cs
@@ -7,7 +7,7 @@ using Artemis.Core.Events;
namespace Artemis.Core
{
///
- public abstract class PinCollection : IPinCollection
+ public abstract class PinCollection : CorePropertyChanged, IPinCollection
{
#region Constructors
diff --git a/src/Avalonia/Artemis.UI.Shared/Controls/DataModelPicker/DataModelPicker.cs b/src/Avalonia/Artemis.UI.Shared/Controls/DataModelPicker/DataModelPicker.cs
index d8efea8de..0a9f50f3e 100644
--- a/src/Avalonia/Artemis.UI.Shared/Controls/DataModelPicker/DataModelPicker.cs
+++ b/src/Avalonia/Artemis.UI.Shared/Controls/DataModelPicker/DataModelPicker.cs
@@ -7,6 +7,7 @@ using Artemis.Core;
using Artemis.Core.Modules;
using Artemis.UI.Shared.DataModelVisualization.Shared;
using Artemis.UI.Shared.Events;
+using Artemis.UI.Shared.Extensions;
using Artemis.UI.Shared.Services.Interfaces;
using Avalonia;
using Avalonia.Controls;
@@ -267,8 +268,10 @@ public class DataModelPicker : TemplatedControl
if (selected is DataModelPropertyViewModel property && property.DataModelPath != null)
DataModelPath = new DataModelPath(property.DataModelPath);
- if (selected is DataModelListViewModel list && list.DataModelPath != null)
+ else if (selected is DataModelListViewModel list && list.DataModelPath != null)
DataModelPath = new DataModelPath(list.DataModelPath);
+ else if (selected is DataModelEventViewModel dataModelEvent && dataModelEvent.DataModelPath != null)
+ DataModelPath = new DataModelPath(dataModelEvent.DataModelPath);
}
private void UpdateCurrentPath(bool selectCurrentPath)
@@ -292,24 +295,8 @@ public class DataModelPicker : TemplatedControl
_currentPathDisplay.Text = string.Join(" › ", DataModelPath.Segments.Where(s => s.GetPropertyDescription() != null).Select(s => s.GetPropertyDescription()!.Name));
if (_currentPathDescription != null)
_currentPathDescription.Text = DataModelPath.GetPropertyDescription()?.Description;
-
if (_currentPathIcon != null)
- {
- Type? type = DataModelPath.GetPropertyType();
- if (type == null)
- _currentPathIcon.Kind = MaterialIconKind.QuestionMarkCircle;
- else if (type.TypeIsNumber())
- _currentPathIcon.Kind = MaterialIconKind.CalculatorVariantOutline;
- else if (type.IsEnum)
- _currentPathIcon.Kind = MaterialIconKind.FormatListBulletedSquare;
- else if (type == typeof(bool))
- _currentPathIcon.Kind = MaterialIconKind.CircleHalfFull;
- else if (type == typeof(string))
- _currentPathIcon.Kind = MaterialIconKind.Text;
- else if (type == typeof(SKColor))
- _currentPathIcon.Kind = MaterialIconKind.Palette;
- else
- _currentPathIcon.Kind = MaterialIconKind.Matrix;
- }
+ _currentPathIcon.Kind = DataModelPath.GetPropertyType().GetTypeIcon();
+
}
}
\ No newline at end of file
diff --git a/src/Avalonia/Artemis.UI.Shared/Controls/DataModelPicker/DataModelPickerButton.cs b/src/Avalonia/Artemis.UI.Shared/Controls/DataModelPicker/DataModelPickerButton.cs
index 3fd1786e9..2955c92f4 100644
--- a/src/Avalonia/Artemis.UI.Shared/Controls/DataModelPicker/DataModelPickerButton.cs
+++ b/src/Avalonia/Artemis.UI.Shared/Controls/DataModelPicker/DataModelPickerButton.cs
@@ -32,6 +32,12 @@ public class DataModelPickerButton : TemplatedControl
public static readonly StyledProperty ShowFullPathProperty =
AvaloniaProperty.Register(nameof(ShowFullPath));
+ ///
+ /// Gets or sets a boolean indicating whether the button should show the icon of the first provided filter type.
+ ///
+ public static readonly StyledProperty ShowTypeIconProperty =
+ AvaloniaProperty.Register(nameof(ShowTypeIcon));
+
///
/// Gets a boolean indicating whether the data model picker has a value.
///
@@ -77,6 +83,7 @@ public class DataModelPickerButton : TemplatedControl
private bool _attached;
private bool _flyoutActive;
private Button? _button;
+ private TextBlock? _label;
private DataModelPickerFlyout? _flyout;
static DataModelPickerButton()
@@ -103,6 +110,16 @@ public class DataModelPickerButton : TemplatedControl
set => SetValue(ShowFullPathProperty, value);
}
+
+ ///
+ /// Gets or sets a boolean indicating whether the button should show the icon of the first provided filter type.
+ ///
+ public bool ShowTypeIcon
+ {
+ get => GetValue(ShowTypeIconProperty);
+ set => SetValue(ShowTypeIconProperty, value);
+ }
+
///
/// Gets a boolean indicating whether the data model picker has a value.
///
@@ -212,13 +229,13 @@ public class DataModelPickerButton : TemplatedControl
{
HasValue = DataModelPath != null && DataModelPath.IsValid;
- if (_button == null)
+ if (_button == null || _label == null)
return;
if (!HasValue)
{
ToolTip.SetTip(_button, null);
- _button.Content = Placeholder;
+ _label.Text = Placeholder;
}
else
{
@@ -227,7 +244,7 @@ public class DataModelPickerButton : TemplatedControl
formattedPath = string.Join(" › ", DataModelPath.Segments.Where(s => s.GetPropertyDescription() != null).Select(s => s.GetPropertyDescription()!.Name));
ToolTip.SetTip(_button, formattedPath);
- _button.Content = ShowFullPath
+ _label.Text = ShowFullPath
? formattedPath
: DataModelPath?.Segments.LastOrDefault()?.GetPropertyDescription()?.Name ?? DataModelPath?.Segments.LastOrDefault()?.Identifier;
}
@@ -261,6 +278,7 @@ public class DataModelPickerButton : TemplatedControl
_button.Click -= OnButtonClick;
base.OnApplyTemplate(e);
_button = e.NameScope.Find