mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Nodes - Made types mutable for non-generic pins/collections
This commit is contained in:
parent
30ec28a9a9
commit
f824f16658
@ -257,7 +257,7 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Returns a boolean indicating whether the provided type can be used as a <see cref="Numeric" />.
|
||||
/// </summary>
|
||||
public static bool IsTypeCompatible(Type type)
|
||||
public static bool IsTypeCompatible(Type? type)
|
||||
{
|
||||
return type == typeof(Numeric) ||
|
||||
type == typeof(float) ||
|
||||
|
||||
@ -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
|
||||
|
||||
/// <summary>
|
||||
/// Changes the type of this pin, disconnecting any pins that are incompatible with the new type.
|
||||
/// </summary>
|
||||
/// <param name="type">The new type of the pin.</param>
|
||||
public void ChangeType(Type type)
|
||||
{
|
||||
if (_type == type)
|
||||
return;
|
||||
|
||||
// Disconnect pins incompatible with the new type
|
||||
List<IPin> 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
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Type Type { get; }
|
||||
public override Type Type => _type;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object? PinValue => Value;
|
||||
@ -113,6 +134,7 @@ namespace Artemis.Core
|
||||
public override PinDirection Direction => PinDirection.Input;
|
||||
|
||||
private object? _value;
|
||||
private Type _type;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the input pin
|
||||
|
||||
@ -59,12 +59,14 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// Changes the type of this pin, disconnecting any pins that are incompatible with the new type.
|
||||
/// </summary>
|
||||
/// <param name="type">The new type of the pin.</param>
|
||||
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));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IPin CreatePin()
|
||||
{
|
||||
@ -89,17 +105,12 @@ namespace Artemis.Core
|
||||
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>();
|
||||
public override Type Type => _type;
|
||||
|
||||
/// <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);
|
||||
public IEnumerable Values => Pins.Where(p => p.PinValue != null).Select(p => p.PinValue);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@ -75,5 +75,12 @@ namespace Artemis.Core
|
||||
/// Disconnects all pins this pin is connected to
|
||||
/// </summary>
|
||||
void DisconnectAll();
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this pin is compatible with the given type
|
||||
/// </summary>
|
||||
/// <param name="type">The type to check for compatibility</param>
|
||||
/// <returns><see langword="true"/> if the type is compatible, otherwise <see langword="false"/>.</returns>
|
||||
public bool IsTypeCompatible(Type type);
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
/// <summary>
|
||||
/// Changes the type of this pin, disconnecting any pins that are incompatible with the new type.
|
||||
/// </summary>
|
||||
/// <param name="type">The new type of the pin.</param>
|
||||
public void ChangeType(Type type)
|
||||
{
|
||||
// Disconnect pins incompatible with the new type
|
||||
List<IPin> 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
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Type Type { get; }
|
||||
public override Type Type => _type;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object? PinValue => Value;
|
||||
@ -84,6 +106,7 @@ namespace Artemis.Core
|
||||
public override PinDirection Direction => PinDirection.Output;
|
||||
|
||||
private object? _value;
|
||||
private Type _type;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the output pin
|
||||
|
||||
@ -101,6 +101,9 @@ namespace Artemis.Core
|
||||
/// <inheritdoc />
|
||||
public void DisconnectAll()
|
||||
{
|
||||
if (!_connectedTo.Any())
|
||||
return;
|
||||
|
||||
List<IPin> connectedPins = new(_connectedTo);
|
||||
_connectedTo.Clear();
|
||||
|
||||
@ -114,6 +117,12 @@ namespace Artemis.Core
|
||||
OnPropertyChanged(nameof(ConnectedTo));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,7 @@ using Artemis.Core.Events;
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <inheritdoc cref="IPinCollection"/>
|
||||
public abstract class PinCollection : IPinCollection
|
||||
public abstract class PinCollection : CorePropertyChanged, IPinCollection
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
}
|
||||
}
|
||||
@ -32,6 +32,12 @@ public class DataModelPickerButton : TemplatedControl
|
||||
public static readonly StyledProperty<bool> ShowFullPathProperty =
|
||||
AvaloniaProperty.Register<DataModelPicker, bool>(nameof(ShowFullPath));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether the button should show the icon of the first provided filter type.
|
||||
/// </summary>
|
||||
public static readonly StyledProperty<bool> ShowTypeIconProperty =
|
||||
AvaloniaProperty.Register<DataModelPicker, bool>(nameof(ShowTypeIcon));
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether the data model picker has a value.
|
||||
/// </summary>
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether the button should show the icon of the first provided filter type.
|
||||
/// </summary>
|
||||
public bool ShowTypeIcon
|
||||
{
|
||||
get => GetValue(ShowTypeIconProperty);
|
||||
set => SetValue(ShowTypeIconProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether the data model picker has a value.
|
||||
/// </summary>
|
||||
@ -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<Button>("MainButton");
|
||||
_label = e.NameScope.Find<TextBlock>("MainButtonLabel");
|
||||
if (_button != null)
|
||||
_button.Click += OnButtonClick;
|
||||
UpdateValueDisplay();
|
||||
|
||||
37
src/Avalonia/Artemis.UI.Shared/Extensions/TypeExtensions.cs
Normal file
37
src/Avalonia/Artemis.UI.Shared/Extensions/TypeExtensions.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using Artemis.Core;
|
||||
using Material.Icons;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
|
||||
namespace Artemis.UI.Shared.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides utilities when working with types in UI elements.
|
||||
/// </summary>
|
||||
public static class TypeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Finds an appropriate Material Design icon for the given <paramref name="type"/>.
|
||||
/// </summary>
|
||||
/// <param name="type">The type to retrieve an icon for.</param>
|
||||
/// <returns>An appropriate Material Design icon for the given <paramref name="type"/>.</returns>
|
||||
public static MaterialIconKind GetTypeIcon(this Type? type)
|
||||
{
|
||||
if (type == null)
|
||||
return MaterialIconKind.QuestionMarkCircle;
|
||||
if (type.TypeIsNumber())
|
||||
return MaterialIconKind.CalculatorVariantOutline;
|
||||
if (type.IsEnum)
|
||||
return MaterialIconKind.FormatListBulletedSquare;
|
||||
if (type == typeof(bool))
|
||||
return MaterialIconKind.CircleHalfFull;
|
||||
if (type == typeof(string))
|
||||
return MaterialIconKind.Text;
|
||||
if (type == typeof(SKColor))
|
||||
return MaterialIconKind.Palette;
|
||||
if (type.IsAssignableTo(typeof(IDataModelEvent)))
|
||||
return MaterialIconKind.LightningBolt;
|
||||
return MaterialIconKind.Matrix;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,8 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:controls1="clr-namespace:Artemis.UI.Shared.Controls"
|
||||
xmlns:gradientPicker="clr-namespace:Artemis.UI.Shared.Controls.GradientPicker">
|
||||
xmlns:gradientPicker="clr-namespace:Artemis.UI.Shared.Controls.GradientPicker"
|
||||
xmlns:dataModelPicker="clr-namespace:Artemis.UI.Shared.Controls.DataModelPicker">
|
||||
<Design.PreviewWith>
|
||||
<Border Padding="50">
|
||||
<StackPanel Spacing="5">
|
||||
@ -32,6 +33,9 @@
|
||||
|
||||
<gradientPicker:GradientPickerButton></gradientPicker:GradientPickerButton>
|
||||
<gradientPicker:GradientPickerButton Classes="condensed"></gradientPicker:GradientPickerButton>
|
||||
|
||||
<dataModelPicker:DataModelPickerButton></dataModelPicker:DataModelPickerButton>
|
||||
<dataModelPicker:DataModelPickerButton Classes="condensed"></dataModelPicker:DataModelPickerButton>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Design.PreviewWith>
|
||||
@ -79,4 +83,15 @@
|
||||
<Setter Property="Margin" Value="4" />
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="dataModelPicker|DataModelPickerButton.condensed">
|
||||
<Setter Property="Padding" Value="4 2" />
|
||||
<Setter Property="FontSize" Value="13" />
|
||||
<Setter Property="MinHeight" Value="24" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="dataModelPicker|DataModelPickerButton.condensed /template/ controls|Button">
|
||||
<Setter Property="Padding" Value="6 3 11 3" />
|
||||
<Setter Property="Height" Value="24" />
|
||||
</Style>
|
||||
</Styles>
|
||||
@ -1,17 +1,18 @@
|
||||
<Styles xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:dataModelPicker="clr-namespace:Artemis.UI.Shared.Controls.DataModelPicker"
|
||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia">
|
||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:gradientPicker="clr-namespace:Artemis.UI.Shared.Controls.GradientPicker">
|
||||
<Design.PreviewWith>
|
||||
<Border Padding="20" Width="200">
|
||||
<StackPanel Spacing="5">
|
||||
<dataModelPicker:DataModelPickerButton />
|
||||
<gradientPicker:GradientPickerButton />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Design.PreviewWith>
|
||||
|
||||
<Style Selector="FlyoutPresenter.data-model-picker-presenter">
|
||||
<!-- <Setter Property="Padding" Value="0" /> -->
|
||||
<Setter Property="MaxWidth" Value="1200" />
|
||||
<Setter Property="MaxHeight" Value="1200" />
|
||||
<Setter Property="Background" Value="{DynamicResource SolidBackgroundFillColorBaseBrush}" />
|
||||
@ -28,7 +29,25 @@
|
||||
<ControlTemplate>
|
||||
<controls:Button Name="MainButton"
|
||||
CornerRadius="{TemplateBinding CornerRadius}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}">
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
VerticalAlignment="{TemplateBinding VerticalAlignment}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
||||
HorizontalContentAlignment="Stretch">
|
||||
<Grid ColumnDefinitions="*,Auto" HorizontalAlignment="Stretch">
|
||||
<TextBlock Name="MainButtonLabel"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
TextAlignment="Left" />
|
||||
<TextBlock Name="ChevronTextBlock"
|
||||
Grid.Column="1"
|
||||
FontFamily="{DynamicResource SymbolThemeFontFamily}"
|
||||
FontSize="13"
|
||||
Text=""
|
||||
VerticalAlignment="Center"
|
||||
TextAlignment="Right"
|
||||
Padding="2 2 2 0"
|
||||
Margin="5 0" />
|
||||
</Grid>
|
||||
</controls:Button>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
|
||||
@ -99,11 +99,7 @@ namespace Artemis.UI.Ninject.Factories
|
||||
DragCableViewModel DragCableViewModel(PinViewModel pinViewModel);
|
||||
InputPinViewModel InputPinViewModel(IPin inputPin);
|
||||
OutputPinViewModel OutputPinViewModel(IPin outputPin);
|
||||
}
|
||||
|
||||
public interface INodePinVmFactory
|
||||
{
|
||||
PinCollectionViewModel InputPinCollectionViewModel(IPinCollection inputPinCollection, NodeScriptViewModel nodeScriptViewModel);
|
||||
PinCollectionViewModel OutputPinCollectionViewModel(IPinCollection outputPinCollection, NodeScriptViewModel nodeScriptViewModel);
|
||||
InputPinCollectionViewModel InputPinCollectionViewModel(IPinCollection inputPinCollection, NodeScriptViewModel nodeScriptViewModel);
|
||||
OutputPinCollectionViewModel OutputPinCollectionViewModel(IPinCollection outputPinCollection, NodeScriptViewModel nodeScriptViewModel);
|
||||
}
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Screens.VisualScripting.Pins;
|
||||
using Ninject.Extensions.Factory;
|
||||
|
||||
namespace Artemis.UI.Ninject.InstanceProviders;
|
||||
|
||||
public class NodePinViewModelInstanceProvider : StandardInstanceProvider
|
||||
{
|
||||
protected override Type GetType(MethodInfo methodInfo, object[] arguments)
|
||||
{
|
||||
if (methodInfo.ReturnType != typeof(PinCollectionViewModel))
|
||||
return base.GetType(methodInfo, arguments);
|
||||
|
||||
if (arguments[0] is IPinCollection pinCollection)
|
||||
return CreatePinCollectionViewModelType(pinCollection);
|
||||
|
||||
return base.GetType(methodInfo, arguments);
|
||||
}
|
||||
|
||||
private Type CreatePinCollectionViewModelType(IPinCollection pinCollection)
|
||||
{
|
||||
if (pinCollection.Direction == PinDirection.Input)
|
||||
return typeof(InputPinCollectionViewModel<>).MakeGenericType(pinCollection.Type);
|
||||
return typeof(OutputPinCollectionViewModel<>).MakeGenericType(pinCollection.Type);
|
||||
}
|
||||
}
|
||||
@ -59,7 +59,6 @@ namespace Artemis.UI.Ninject
|
||||
});
|
||||
|
||||
Kernel.Bind<IPropertyVmFactory>().ToFactory(() => new LayerPropertyViewModelInstanceProvider());
|
||||
Kernel.Bind<INodePinVmFactory>().ToFactory(() => new NodePinViewModelInstanceProvider());
|
||||
|
||||
// Bind all UI services as singletons
|
||||
Kernel.Bind(x =>
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||
xmlns:skiaSharp="clr-namespace:SkiaSharp;assembly=SkiaSharp"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
|
||||
xmlns:system="clr-namespace:System;assembly=System.Runtime"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.VisualScripting.CableView"
|
||||
x:DataType="visualScripting:CableViewModel"
|
||||
@ -45,7 +46,8 @@
|
||||
CornerRadius="3"
|
||||
Padding="4"
|
||||
Canvas.Left="{CompiledBinding ValuePoint.X}"
|
||||
Canvas.Top="{CompiledBinding ValuePoint.Y}">
|
||||
Canvas.Top="{CompiledBinding ValuePoint.Y}"
|
||||
IsVisible="{CompiledBinding FromViewModel.Pin.PinValue, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<ContentControl Content="{CompiledBinding FromViewModel.Pin.PinValue}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="skiaSharp:SKColor">
|
||||
|
||||
@ -16,14 +16,14 @@ namespace Artemis.UI.Screens.VisualScripting;
|
||||
public class CableViewModel : ActivatableViewModelBase
|
||||
{
|
||||
private readonly ObservableAsPropertyHelper<bool> _connected;
|
||||
private readonly ObservableAsPropertyHelper<Color> _cableColor;
|
||||
private readonly ObservableAsPropertyHelper<Point> _fromPoint;
|
||||
private readonly ObservableAsPropertyHelper<Point> _toPoint;
|
||||
private readonly ObservableAsPropertyHelper<Point> _valuePoint;
|
||||
private ObservableAsPropertyHelper<Color>? _cableColor;
|
||||
|
||||
private PinViewModel? _fromViewModel;
|
||||
private PinViewModel? _toViewModel;
|
||||
|
||||
|
||||
public CableViewModel(NodeScriptViewModel nodeScriptViewModel, IPin from, IPin to)
|
||||
{
|
||||
if (from.Direction != PinDirection.Output)
|
||||
@ -36,6 +36,12 @@ public class CableViewModel : ActivatableViewModelBase
|
||||
{
|
||||
nodeScriptViewModel.PinViewModels.ToObservableChangeSet().Filter(p => ReferenceEquals(p.Pin, from)).Transform(model => FromViewModel = model).Subscribe().DisposeWith(d);
|
||||
nodeScriptViewModel.PinViewModels.ToObservableChangeSet().Filter(p => ReferenceEquals(p.Pin, to)).Transform(model => ToViewModel = model).Subscribe().DisposeWith(d);
|
||||
|
||||
_cableColor = this.WhenAnyValue(vm => vm.FromViewModel, vm => vm.ToViewModel)
|
||||
.Select(tuple => tuple.Item1?.WhenAnyValue(p => p.PinColor) ?? tuple.Item2?.WhenAnyValue(p => p.PinColor) ?? Observable.Never<Color>())
|
||||
.Switch()
|
||||
.ToProperty(this, vm => vm.CableColor)
|
||||
.DisposeWith(d);
|
||||
});
|
||||
|
||||
_fromPoint = this.WhenAnyValue(vm => vm.FromViewModel)
|
||||
@ -51,10 +57,6 @@ public class CableViewModel : ActivatableViewModelBase
|
||||
tuple.Item1.Y + (tuple.Item2.Y - tuple.Item1.Y) / 2
|
||||
)).ToProperty(this, vm => vm.ValuePoint);
|
||||
|
||||
_cableColor = this.WhenAnyValue(vm => vm.FromViewModel, vm => vm.ToViewModel)
|
||||
.Select(tuple => tuple.Item1?.PinColor ?? tuple.Item2?.PinColor ?? new Color(255, 255, 255, 255))
|
||||
.ToProperty(this, vm => vm.CableColor);
|
||||
|
||||
// Not a perfect solution but this makes sure the cable never renders at 0,0 (can happen when the cable spawns before the pin ever rendered)
|
||||
_connected = this.WhenAnyValue(vm => vm.FromPoint, vm => vm.ToPoint)
|
||||
.Select(tuple => tuple.Item1 != new Point(0, 0) && tuple.Item2 != new Point(0, 0))
|
||||
@ -78,5 +80,5 @@ public class CableViewModel : ActivatableViewModelBase
|
||||
public Point FromPoint => _fromPoint.Value;
|
||||
public Point ToPoint => _toPoint.Value;
|
||||
public Point ValuePoint => _valuePoint.Value;
|
||||
public Color CableColor => _cableColor.Value;
|
||||
public Color CableColor => _cableColor?.Value ?? new Color(255, 255, 255, 255);
|
||||
}
|
||||
@ -64,6 +64,7 @@ public class NodeScriptViewModel : ActivatableViewModelBase
|
||||
PinViewModels.ToObservableChangeSet()
|
||||
.Filter(p => p.Pin.Direction == PinDirection.Output)
|
||||
.TransformMany(p => p.Connections)
|
||||
.Filter(p => p.ConnectedTo.Any())
|
||||
.Transform(pin => _nodeVmFactory.CableViewModel(this, pin.ConnectedTo.First(), pin))
|
||||
.Bind(out ReadOnlyObservableCollection<CableViewModel> cableViewModels)
|
||||
.Subscribe();
|
||||
|
||||
@ -33,7 +33,7 @@ public class NodeViewModel : ActivatableViewModelBase
|
||||
private ObservableAsPropertyHelper<bool>? _hasInputPins;
|
||||
private ObservableAsPropertyHelper<bool>? _hasOutputPins;
|
||||
|
||||
public NodeViewModel(NodeScriptViewModel nodeScriptViewModel, INode node, INodeVmFactory nodeVmFactory, INodePinVmFactory nodePinVmFactory, INodeEditorService nodeEditorService)
|
||||
public NodeViewModel(NodeScriptViewModel nodeScriptViewModel, INode node, INodeVmFactory nodeVmFactory, INodeEditorService nodeEditorService)
|
||||
{
|
||||
NodeScriptViewModel = nodeScriptViewModel;
|
||||
_nodeEditorService = nodeEditorService;
|
||||
@ -61,12 +61,12 @@ public class NodeViewModel : ActivatableViewModelBase
|
||||
// Same again but for pin collections
|
||||
nodePinCollections.Connect()
|
||||
.Filter(n => n.Direction == PinDirection.Input)
|
||||
.Transform(c => nodePinVmFactory.InputPinCollectionViewModel(c, nodeScriptViewModel))
|
||||
.Transform(c => (PinCollectionViewModel) nodeVmFactory.InputPinCollectionViewModel(c, nodeScriptViewModel))
|
||||
.Bind(out ReadOnlyObservableCollection<PinCollectionViewModel> inputPinCollections)
|
||||
.Subscribe();
|
||||
nodePinCollections.Connect()
|
||||
.Filter(n => n.Direction == PinDirection.Output)
|
||||
.Transform(c => nodePinVmFactory.OutputPinCollectionViewModel(c, nodeScriptViewModel))
|
||||
.Transform(c => (PinCollectionViewModel) nodeVmFactory.OutputPinCollectionViewModel(c, nodeScriptViewModel))
|
||||
.Bind(out ReadOnlyObservableCollection<PinCollectionViewModel> outputPinCollections)
|
||||
.Subscribe();
|
||||
InputPinCollectionViewModels = inputPinCollections;
|
||||
|
||||
@ -4,12 +4,12 @@ using Artemis.UI.Shared.Services.NodeEditor;
|
||||
|
||||
namespace Artemis.UI.Screens.VisualScripting.Pins;
|
||||
|
||||
public class InputPinCollectionViewModel<T> : PinCollectionViewModel
|
||||
public class InputPinCollectionViewModel : PinCollectionViewModel
|
||||
{
|
||||
private readonly INodeVmFactory _nodeVmFactory;
|
||||
public InputPinCollection<T> InputPinCollection { get; }
|
||||
public IPinCollection InputPinCollection { get; }
|
||||
|
||||
public InputPinCollectionViewModel(InputPinCollection<T> inputPinCollection, NodeScriptViewModel nodeScriptViewModel, INodeVmFactory nodeVmFactory, INodeEditorService nodeEditorService)
|
||||
public InputPinCollectionViewModel(IPinCollection inputPinCollection, NodeScriptViewModel nodeScriptViewModel, INodeVmFactory nodeVmFactory, INodeEditorService nodeEditorService)
|
||||
: base(inputPinCollection, nodeScriptViewModel, nodeEditorService)
|
||||
{
|
||||
_nodeVmFactory = nodeVmFactory;
|
||||
|
||||
@ -4,12 +4,12 @@ using Artemis.UI.Shared.Services.NodeEditor;
|
||||
|
||||
namespace Artemis.UI.Screens.VisualScripting.Pins;
|
||||
|
||||
public class OutputPinCollectionViewModel<T> : PinCollectionViewModel
|
||||
public class OutputPinCollectionViewModel : PinCollectionViewModel
|
||||
{
|
||||
private readonly INodeVmFactory _nodeVmFactory;
|
||||
public OutputPinCollection<T> OutputPinCollection { get; }
|
||||
public IPinCollection OutputPinCollection { get; }
|
||||
|
||||
public OutputPinCollectionViewModel(OutputPinCollection<T> outputPinCollection, NodeScriptViewModel nodeScriptViewModel, INodeVmFactory nodeVmFactory, INodeEditorService nodeEditorService)
|
||||
public OutputPinCollectionViewModel(IPinCollection outputPinCollection, NodeScriptViewModel nodeScriptViewModel, INodeVmFactory nodeVmFactory, INodeEditorService nodeEditorService)
|
||||
: base(outputPinCollection, nodeScriptViewModel, nodeEditorService)
|
||||
{
|
||||
_nodeVmFactory = nodeVmFactory;
|
||||
|
||||
@ -16,17 +16,17 @@ namespace Artemis.UI.Screens.VisualScripting.Pins;
|
||||
|
||||
public abstract class PinViewModel : ActivatableViewModelBase
|
||||
{
|
||||
private Point _position;
|
||||
private readonly INodeService _nodeService;
|
||||
private ReactiveCommand<IPin, Unit>? _removePin;
|
||||
private Point _position;
|
||||
private Color _pinColor;
|
||||
private Color _darkenedPinColor;
|
||||
|
||||
protected PinViewModel(IPin pin, INodeService nodeService)
|
||||
{
|
||||
_nodeService = nodeService;
|
||||
|
||||
Pin = pin;
|
||||
|
||||
TypeColorRegistration registration = nodeService.GetTypeColorRegistration(Pin.Type);
|
||||
PinColor = registration.Color.ToColor();
|
||||
DarkenedPinColor = registration.DarkenedColor.ToColor();
|
||||
|
||||
SourceList<IPin> connectedPins = new();
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
@ -36,17 +36,35 @@ public abstract class PinViewModel : ActivatableViewModelBase
|
||||
Observable.FromEventPattern<SingleValueEventArgs<IPin>>(x => Pin.PinDisconnected += x, x => Pin.PinDisconnected -= x)
|
||||
.Subscribe(e => connectedPins.Remove(e.EventArgs.Value))
|
||||
.DisposeWith(d);
|
||||
Pin.WhenAnyValue(p => p.Type).Subscribe(_ => UpdatePinColor()).DisposeWith(d);
|
||||
});
|
||||
|
||||
Connections = connectedPins.Connect().AsObservableList();
|
||||
connectedPins.AddRange(Pin.ConnectedTo);
|
||||
}
|
||||
|
||||
private void UpdatePinColor()
|
||||
{
|
||||
TypeColorRegistration registration = _nodeService.GetTypeColorRegistration(Pin.Type);
|
||||
PinColor = registration.Color.ToColor();
|
||||
DarkenedPinColor = registration.DarkenedColor.ToColor();
|
||||
}
|
||||
|
||||
public IObservableList<IPin> Connections { get; }
|
||||
|
||||
public IPin Pin { get; }
|
||||
public Color PinColor { get; }
|
||||
public Color DarkenedPinColor { get; }
|
||||
|
||||
public Color PinColor
|
||||
{
|
||||
get => _pinColor;
|
||||
set => RaiseAndSetIfChanged(ref _pinColor, value);
|
||||
}
|
||||
|
||||
public Color DarkenedPinColor
|
||||
{
|
||||
get => _darkenedPinColor;
|
||||
set => RaiseAndSetIfChanged(ref _darkenedPinColor, value);
|
||||
}
|
||||
|
||||
public Point Position
|
||||
{
|
||||
@ -62,14 +80,9 @@ public abstract class PinViewModel : ActivatableViewModelBase
|
||||
|
||||
public bool IsCompatibleWith(PinViewModel pinViewModel)
|
||||
{
|
||||
if (pinViewModel.Pin.Direction == Pin.Direction)
|
||||
return false;
|
||||
if (pinViewModel.Pin.Node == Pin.Node)
|
||||
if (pinViewModel.Pin.Direction == Pin.Direction || pinViewModel.Pin.Node == Pin.Node)
|
||||
return false;
|
||||
|
||||
return Pin.Type == pinViewModel.Pin.Type
|
||||
|| Pin.Type == typeof(Enum) && pinViewModel.Pin.Type.IsEnum
|
||||
|| Pin.Direction == PinDirection.Input && Pin.Type == typeof(object)
|
||||
|| Pin.Direction == PinDirection.Output && pinViewModel.Pin.Type == typeof(object);
|
||||
return Pin.IsTypeCompatible(pinViewModel.Pin.Type);
|
||||
}
|
||||
}
|
||||
@ -27,9 +27,9 @@ public class DataModelNodeCustomViewModel : CustomNodeViewModel
|
||||
return;
|
||||
|
||||
Modules = new ObservableCollection<Module>();
|
||||
if (_node.Script.Context is Profile scriptProfile && scriptProfile.Configuration.Module != null)
|
||||
if (_node.Script?.Context is Profile scriptProfile && scriptProfile.Configuration.Module != null)
|
||||
Modules.Add(scriptProfile.Configuration.Module);
|
||||
else if (_node.Script.Context is ProfileConfiguration profileConfiguration && profileConfiguration.Module != null)
|
||||
else if (_node.Script?.Context is ProfileConfiguration profileConfiguration && profileConfiguration.Module != null)
|
||||
Modules.Add(profileConfiguration.Module);
|
||||
|
||||
_node.PropertyChanged += NodeOnPropertyChanged;
|
||||
@ -46,7 +46,7 @@ public class DataModelNodeCustomViewModel : CustomNodeViewModel
|
||||
set => RaiseAndSetIfChanged(ref _modules, value);
|
||||
}
|
||||
|
||||
public DataModelPath DataModelPath
|
||||
public DataModelPath? DataModelPath
|
||||
{
|
||||
get => _node.DataModelPath;
|
||||
set
|
||||
@ -56,10 +56,10 @@ public class DataModelNodeCustomViewModel : CustomNodeViewModel
|
||||
|
||||
_node.DataModelPath?.Dispose();
|
||||
_node.DataModelPath = value;
|
||||
_node.DataModelPath.Save();
|
||||
_node.DataModelPath?.Save();
|
||||
|
||||
_node.Storage = _node.DataModelPath.Entity;
|
||||
_node.UpdateOutputPin(false);
|
||||
_node.Storage = _node.DataModelPath?.Entity;
|
||||
_node.UpdateOutputPin();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,8 +7,10 @@
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.VisualScripting.Nodes.DataModel.CustomViews.DataModelEventNodeCustomView"
|
||||
x:DataType="customViewModels:DataModelEventNodeCustomViewModel">
|
||||
<dataModelPicker:DataModelPickerButton DataModelPath="{CompiledBinding DataModelPath}"
|
||||
<dataModelPicker:DataModelPickerButton Classes="condensed"
|
||||
DataModelPath="{CompiledBinding DataModelPath}"
|
||||
Modules="{CompiledBinding Modules}"
|
||||
ShowDataModelValues="{CompiledBinding ShowDataModelValues.Value}"
|
||||
FilterTypes="{CompiledBinding FilterTypes}" />
|
||||
FilterTypes="{CompiledBinding FilterTypes}"
|
||||
VerticalAlignment="Top"/>
|
||||
</UserControl>
|
||||
@ -1,18 +0,0 @@
|
||||
<UserControl x:Class="Artemis.VisualScripting.Nodes.DataModel.CustomViews.DataModelEventNodeCustomView"
|
||||
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:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:DataModelPicker DataModelPath="{Binding DataModelPath}"
|
||||
Modules="{Binding Modules}"
|
||||
ShowFullPath="{Binding ShowFullPaths.Value}"
|
||||
ShowDataModelValues="{Binding ShowDataModelValues.Value}"
|
||||
FilterTypes="{Binding FilterTypes}"
|
||||
ButtonBrush="DarkGoldenrod" />
|
||||
</StackPanel>
|
||||
|
||||
</UserControl>
|
||||
@ -7,7 +7,8 @@
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.VisualScripting.Nodes.DataModel.CustomViews.DataModelNodeCustomView"
|
||||
x:DataType="customViewModels:DataModelNodeCustomViewModel">
|
||||
<dataModelPicker:DataModelPickerButton DataModelPath="{CompiledBinding DataModelPath}"
|
||||
<dataModelPicker:DataModelPickerButton Classes="condensed"
|
||||
DataModelPath="{CompiledBinding DataModelPath}"
|
||||
Modules="{CompiledBinding Modules}"
|
||||
ShowDataModelValues="{CompiledBinding ShowDataModelValues.Value}" />
|
||||
</UserControl>
|
||||
@ -1,14 +0,0 @@
|
||||
<UserControl x:Class="Artemis.VisualScripting.Nodes.DataModel.CustomViews.DataModelNodeCustomView"
|
||||
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:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<controls:DataModelPicker DataModelPath="{Binding DataModelPath}"
|
||||
Modules="{Binding Modules}"
|
||||
ShowFullPath="{Binding ShowFullPaths.Value}"
|
||||
ShowDataModelValues="{Binding ShowDataModelValues.Value}"
|
||||
ButtonBrush="#434343" />
|
||||
</UserControl>
|
||||
@ -10,22 +10,28 @@ public class DataModelEventNode : Node<DataModelPathEntity, DataModelEventNodeCu
|
||||
{
|
||||
private int _currentIndex;
|
||||
private Type _currentType;
|
||||
private DataModelPath _dataModelPath;
|
||||
private DataModelPath? _dataModelPath;
|
||||
private DateTime _lastTrigger;
|
||||
private bool _updating;
|
||||
|
||||
public DataModelEventNode() : base("Data Model-Event", "Responds to a data model event trigger")
|
||||
{
|
||||
_currentType = typeof(object);
|
||||
CreateCycleValues(typeof(object), 1);
|
||||
|
||||
CycleValues = CreateInputPinCollection(typeof(object), "", 0);
|
||||
Output = CreateOutputPin(typeof(object));
|
||||
|
||||
CycleValues.PinAdded += CycleValuesOnPinAdded;
|
||||
CycleValues.PinRemoved += CycleValuesOnPinRemoved;
|
||||
CycleValues.Add(CycleValues.CreatePin());
|
||||
}
|
||||
|
||||
public InputPinCollection CycleValues { get; set; }
|
||||
public OutputPin Output { get; set; }
|
||||
public INodeScript Script { get; set; }
|
||||
public INodeScript? Script { get; set; }
|
||||
|
||||
public DataModelPath DataModelPath
|
||||
public InputPinCollection CycleValues { get; }
|
||||
public OutputPin Output { get; }
|
||||
|
||||
public DataModelPath? DataModelPath
|
||||
{
|
||||
get => _dataModelPath;
|
||||
set => SetAndNotify(ref _dataModelPath, value);
|
||||
@ -43,7 +49,7 @@ public class DataModelEventNode : Node<DataModelPathEntity, DataModelEventNodeCu
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
object outputValue = null;
|
||||
object? outputValue = null;
|
||||
if (DataModelPath?.GetValue() is IDataModelEvent dataModelEvent)
|
||||
{
|
||||
if (dataModelEvent.LastTrigger > _lastTrigger)
|
||||
@ -64,56 +70,29 @@ public class DataModelEventNode : Node<DataModelPathEntity, DataModelEventNodeCu
|
||||
Output.Value = Output.Type.GetDefault()!;
|
||||
}
|
||||
|
||||
private void CreateCycleValues(Type type, int initialCount)
|
||||
{
|
||||
if (CycleValues != null)
|
||||
{
|
||||
CycleValues.PinAdded -= CycleValuesOnPinAdded;
|
||||
CycleValues.PinRemoved -= CycleValuesOnPinRemoved;
|
||||
foreach (IPin pin in CycleValues)
|
||||
{
|
||||
pin.PinConnected -= OnPinConnected;
|
||||
pin.PinDisconnected -= OnPinDisconnected;
|
||||
}
|
||||
|
||||
RemovePinCollection(CycleValues);
|
||||
}
|
||||
|
||||
CycleValues = CreateInputPinCollection(type, "", initialCount);
|
||||
CycleValues.PinAdded += CycleValuesOnPinAdded;
|
||||
CycleValues.PinRemoved += CycleValuesOnPinRemoved;
|
||||
foreach (IPin pin in CycleValues)
|
||||
{
|
||||
pin.PinConnected += OnPinConnected;
|
||||
pin.PinDisconnected += OnPinDisconnected;
|
||||
}
|
||||
}
|
||||
|
||||
private void CycleValuesOnPinAdded(object sender, SingleValueEventArgs<IPin> e)
|
||||
private void CycleValuesOnPinAdded(object? sender, SingleValueEventArgs<IPin> e)
|
||||
{
|
||||
e.Value.PinConnected += OnPinConnected;
|
||||
e.Value.PinDisconnected += OnPinDisconnected;
|
||||
}
|
||||
|
||||
private void CycleValuesOnPinRemoved(object sender, SingleValueEventArgs<IPin> e)
|
||||
private void CycleValuesOnPinRemoved(object? sender, SingleValueEventArgs<IPin> e)
|
||||
{
|
||||
e.Value.PinConnected -= OnPinConnected;
|
||||
e.Value.PinDisconnected -= OnPinDisconnected;
|
||||
}
|
||||
|
||||
private void OnPinDisconnected(object sender, SingleValueEventArgs<IPin> e)
|
||||
private void OnPinDisconnected(object? sender, SingleValueEventArgs<IPin> e)
|
||||
{
|
||||
ProcessPinDisconnected();
|
||||
}
|
||||
|
||||
private void OnPinConnected(object sender, SingleValueEventArgs<IPin> e)
|
||||
private void OnPinConnected(object? sender, SingleValueEventArgs<IPin> e)
|
||||
{
|
||||
IPin source = e.Value;
|
||||
IPin target = (IPin) sender;
|
||||
ProcessPinConnected(source, target);
|
||||
ProcessPinConnected(e.Value);
|
||||
}
|
||||
|
||||
private void ProcessPinConnected(IPin source, IPin target)
|
||||
private void ProcessPinConnected(IPin source)
|
||||
{
|
||||
if (_updating)
|
||||
return;
|
||||
@ -123,17 +102,8 @@ public class DataModelEventNode : Node<DataModelPathEntity, DataModelEventNodeCu
|
||||
_updating = true;
|
||||
|
||||
// No need to change anything if the types haven't changed
|
||||
if (_currentType == source.Type)
|
||||
return;
|
||||
|
||||
int reconnectIndex = CycleValues.ToList().IndexOf(target);
|
||||
ChangeCurrentType(source.Type);
|
||||
|
||||
if (reconnectIndex != -1)
|
||||
{
|
||||
CycleValues.ToList()[reconnectIndex].ConnectTo(source);
|
||||
source.ConnectTo(CycleValues.ToList()[reconnectIndex]);
|
||||
}
|
||||
if (_currentType != source.Type)
|
||||
ChangeCurrentType(source.Type);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -143,17 +113,8 @@ public class DataModelEventNode : Node<DataModelPathEntity, DataModelEventNodeCu
|
||||
|
||||
private void ChangeCurrentType(Type type)
|
||||
{
|
||||
CreateCycleValues(type, CycleValues.Count());
|
||||
|
||||
List<IPin> oldOutputConnections = Output.ConnectedTo.ToList();
|
||||
RemovePin(Output);
|
||||
Output = CreateOutputPin(type);
|
||||
foreach (IPin oldOutputConnection in oldOutputConnections.Where(o => o.Type.IsAssignableFrom(Output.Type)))
|
||||
{
|
||||
oldOutputConnection.DisconnectAll();
|
||||
oldOutputConnection.ConnectTo(Output);
|
||||
Output.ConnectTo(oldOutputConnection);
|
||||
}
|
||||
CycleValues.ChangeType(type);
|
||||
Output.ChangeType(type);
|
||||
|
||||
_currentType = type;
|
||||
}
|
||||
@ -176,10 +137,6 @@ public class DataModelEventNode : Node<DataModelPathEntity, DataModelEventNodeCu
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePinsType(IPin source)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
@ -8,16 +8,17 @@ namespace Artemis.VisualScripting.Nodes.DataModel;
|
||||
[Node("Data Model-Value", "Outputs a selectable data model value.", "Data Model")]
|
||||
public class DataModelNode : Node<DataModelPathEntity, DataModelNodeCustomViewModel>, IDisposable
|
||||
{
|
||||
private DataModelPath _dataModelPath;
|
||||
private DataModelPath? _dataModelPath;
|
||||
|
||||
public DataModelNode() : base("Data Model", "Outputs a selectable data model value")
|
||||
{
|
||||
Output = CreateOutputPin(typeof(object));
|
||||
}
|
||||
|
||||
public INodeScript Script { get; private set; }
|
||||
public OutputPin Output { get; private set; }
|
||||
public INodeScript? Script { get; private set; }
|
||||
public OutputPin Output { get; }
|
||||
|
||||
public DataModelPath DataModelPath
|
||||
public DataModelPath? DataModelPath
|
||||
{
|
||||
get => _dataModelPath;
|
||||
set => SetAndNotify(ref _dataModelPath, value);
|
||||
@ -33,58 +34,40 @@ public class DataModelNode : Node<DataModelPathEntity, DataModelNodeCustomViewMo
|
||||
DataModelPath = new DataModelPath(Storage);
|
||||
DataModelPath.PathValidated += DataModelPathOnPathValidated;
|
||||
|
||||
UpdateOutputPin(false);
|
||||
UpdateOutputPin();
|
||||
}
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
if (DataModelPath.IsValid)
|
||||
{
|
||||
if (Output == null)
|
||||
UpdateOutputPin(false);
|
||||
|
||||
object pathValue = DataModelPath.GetValue();
|
||||
|
||||
if (pathValue == null)
|
||||
{
|
||||
if (!Output.Type.IsValueType)
|
||||
Output.Value = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Output.Type == typeof(Numeric))
|
||||
Output.Value = new Numeric(pathValue);
|
||||
else
|
||||
Output.Value = pathValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateOutputPin(bool loadConnections)
|
||||
{
|
||||
Type type = DataModelPath?.GetPropertyType();
|
||||
if (Numeric.IsTypeCompatible(type))
|
||||
type = typeof(Numeric);
|
||||
|
||||
if (Output != null && Output.Type == type)
|
||||
if (DataModelPath == null || !DataModelPath.IsValid)
|
||||
return;
|
||||
|
||||
if (Output != null)
|
||||
object? pathValue = DataModelPath.GetValue();
|
||||
if (pathValue == null)
|
||||
{
|
||||
RemovePin(Output);
|
||||
Output = null;
|
||||
if (!Output.Type.IsValueType)
|
||||
Output.Value = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
Output.Value = Output.Type == typeof(Numeric) ? new Numeric(pathValue) : pathValue;
|
||||
}
|
||||
|
||||
if (type != null)
|
||||
Output = CreateOutputPin(type);
|
||||
|
||||
if (loadConnections && Script is NodeScript nodeScript)
|
||||
nodeScript.LoadConnections();
|
||||
}
|
||||
|
||||
private void DataModelPathOnPathValidated(object sender, EventArgs e)
|
||||
public void UpdateOutputPin()
|
||||
{
|
||||
Dispatcher.UIThread.InvokeAsync(() => UpdateOutputPin(true));
|
||||
Type? type = DataModelPath?.GetPropertyType();
|
||||
if (Numeric.IsTypeCompatible(type))
|
||||
type = typeof(Numeric);
|
||||
type ??= typeof(object);
|
||||
|
||||
if (Output.Type != type)
|
||||
Output.ChangeType(type);
|
||||
}
|
||||
|
||||
private void DataModelPathOnPathValidated(object? sender, EventArgs e)
|
||||
{
|
||||
Dispatcher.UIThread.InvokeAsync(UpdateOutputPin);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user