mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 03:48:56 +00:00
Meta - Replace WPF projects with Avalonia projects
This commit is contained in:
1 parent
fcf0376a9a
commit
d7f3ee1190
1110 files changed
+10872
-52240
No files matched your search
@@ -1,55 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<PreserveCompilationContext>false</PreserveCompilationContext>
|
||||
<ShouldIncludeNativeSkiaSharp>false</ShouldIncludeNativeSkiaSharp>
|
||||
<AssemblyTitle>Artemis.VisualScripting</AssemblyTitle>
|
||||
<Product>Artemis Visual-Scripting</Product>
|
||||
<Copyright>Copyright © Darth Affe - 2021</Copyright>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Platforms>x64</Platforms>
|
||||
<UseWPF>true</UseWPF>
|
||||
<Nullable>disable</Nullable>
|
||||
<AnalysisLevel>latest</AnalysisLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<DocumentationFile></DocumentationFile>
|
||||
<NoWarn></NoWarn>
|
||||
<WarningLevel>5</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<NrtRevisionFormat>1.0-{chash:6}</NrtRevisionFormat>
|
||||
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
|
||||
<NrtResolveInformationalAttribute>true</NrtResolveInformationalAttribute>
|
||||
<NrtResolveCopyright>true</NrtResolveCopyright>
|
||||
<NrtTagMatch>v[0-9]*</NrtTagMatch>
|
||||
<NrtRemoveTagV>true</NrtRemoveTagV>
|
||||
<NrtRequiredVcs>git</NrtRequiredVcs>
|
||||
<NrtShowRevision>true</NrtShowRevision>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<DocumentationFile>bin\Artemis.VisualScripting.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Include="Properties\DesignTimeResources.xaml" Condition="'$(DesignTime)'=='true' OR ('$(SolutionPath)'!='' AND Exists('$(SolutionPath)') AND '$(BuildingInsideVisualStudio)'!='true' AND '$(BuildingInsideExpressionBlend)'!='true')">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
<ContainsDesignTimeResources>true</ContainsDesignTimeResources>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2021.1.0" />
|
||||
<PackageReference Include="MaterialDesignThemes" Version="4.1.0" />
|
||||
<PackageReference Include="Avalonia" Version="0.10.13" />
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.13" />
|
||||
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="0.10.13.2" />
|
||||
<PackageReference Include="Ninject" Version="3.3.4" />
|
||||
<PackageReference Include="NoStringEvaluating" Version="2.2.2" />
|
||||
<PackageReference Include="ReactiveUI" Version="17.1.50" />
|
||||
<PackageReference Include="SkiaSharp" Version="2.88.0-preview.178" />
|
||||
<PackageReference Include="Stylet" Version="1.3.6" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -58,18 +23,12 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="Editor\EditorStyles.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Nodes\DataModel\CustomViews\DataModelEventNodeCustomView.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
<Page Update="Nodes\CustomViews\StaticNumericValueNodeCustomView.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
<Page Update="ResourceDictionaries\DataModelConditions.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
<Compile Update="Nodes\CustomViews\StaticStringValueNodeCustomView.axaml.cs">
|
||||
<DependentUpon>StaticStringValueNodeCustomView.axaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Nodes\DataModel\CustomViews\DataModelNodeCustomView.axaml.cs">
|
||||
<DependentUpon>DataModelNodeCustomView.axaml</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
</Project>
|
||||
@@ -1,169 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Artemis.VisualScripting.Behaviors
|
||||
{
|
||||
// Source: https://stackoverflow.com/a/60474831/5015269
|
||||
// Made some changes to add a foreground and background property
|
||||
public static class HighlightTermBehavior
|
||||
{
|
||||
public static readonly DependencyProperty TextProperty = DependencyProperty.RegisterAttached(
|
||||
"Text",
|
||||
typeof(string),
|
||||
typeof(HighlightTermBehavior),
|
||||
new FrameworkPropertyMetadata("", OnTextChanged));
|
||||
|
||||
public static readonly DependencyProperty TermToBeHighlightedProperty = DependencyProperty.RegisterAttached(
|
||||
"TermToBeHighlighted",
|
||||
typeof(string),
|
||||
typeof(HighlightTermBehavior),
|
||||
new FrameworkPropertyMetadata("", OnTextChanged));
|
||||
|
||||
public static readonly DependencyProperty HighlightForegroundProperty = DependencyProperty.RegisterAttached(
|
||||
"HighlightForeground",
|
||||
typeof(Color?),
|
||||
typeof(HighlightTermBehavior),
|
||||
new FrameworkPropertyMetadata(null, OnTextChanged));
|
||||
|
||||
public static readonly DependencyProperty HighlightBackgroundProperty = DependencyProperty.RegisterAttached(
|
||||
"HighlightBackground",
|
||||
typeof(Color?),
|
||||
typeof(HighlightTermBehavior),
|
||||
new FrameworkPropertyMetadata(null, OnTextChanged));
|
||||
|
||||
public static string GetText(FrameworkElement frameworkElement)
|
||||
{
|
||||
return (string) frameworkElement.GetValue(TextProperty);
|
||||
}
|
||||
|
||||
public static void SetText(FrameworkElement frameworkElement, string value)
|
||||
{
|
||||
frameworkElement.SetValue(TextProperty, value);
|
||||
}
|
||||
|
||||
public static string GetTermToBeHighlighted(FrameworkElement frameworkElement)
|
||||
{
|
||||
return (string) frameworkElement.GetValue(TermToBeHighlightedProperty);
|
||||
}
|
||||
|
||||
public static void SetTermToBeHighlighted(FrameworkElement frameworkElement, string value)
|
||||
{
|
||||
frameworkElement.SetValue(TermToBeHighlightedProperty, value);
|
||||
}
|
||||
|
||||
public static void SetHighlightForeground(FrameworkElement frameworkElement, Color? value)
|
||||
{
|
||||
frameworkElement.SetValue(HighlightForegroundProperty, value);
|
||||
}
|
||||
|
||||
public static Color? GetHighlightForeground(FrameworkElement frameworkElement)
|
||||
{
|
||||
return (Color?) frameworkElement.GetValue(HighlightForegroundProperty);
|
||||
}
|
||||
|
||||
public static void SetHighlightBackground(FrameworkElement frameworkElement, Color? value)
|
||||
{
|
||||
frameworkElement.SetValue(HighlightBackgroundProperty, value);
|
||||
}
|
||||
|
||||
public static Color? GetHighlightBackground(FrameworkElement frameworkElement)
|
||||
{
|
||||
return (Color?) frameworkElement.GetValue(HighlightBackgroundProperty);
|
||||
}
|
||||
|
||||
public static List<string> SplitTextIntoTermAndNotTermParts(string text, string term)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return new List<string> {string.Empty};
|
||||
|
||||
return Regex.Split(text, $@"({Regex.Escape(term)})", RegexOptions.IgnoreCase)
|
||||
.Where(p => p != string.Empty)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
||||
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is TextBlock textBlock)
|
||||
SetTextBlockTextAndHighlightTerm(textBlock, GetText(textBlock), GetTermToBeHighlighted(textBlock));
|
||||
}
|
||||
|
||||
private static void SetTextBlockTextAndHighlightTerm(TextBlock textBlock, string text, string termToBeHighlighted)
|
||||
{
|
||||
textBlock.Text = string.Empty;
|
||||
|
||||
if (TextIsEmpty(text))
|
||||
return;
|
||||
|
||||
if (TextIsNotContainingTermToBeHighlighted(text, termToBeHighlighted))
|
||||
{
|
||||
AddPartToTextBlock(textBlock, text);
|
||||
return;
|
||||
}
|
||||
|
||||
List<string> textParts = SplitTextIntoTermAndNotTermParts(text, termToBeHighlighted);
|
||||
|
||||
foreach (string textPart in textParts)
|
||||
AddPartToTextBlockAndHighlightIfNecessary(textBlock, termToBeHighlighted, textPart);
|
||||
}
|
||||
|
||||
private static bool TextIsEmpty(string text)
|
||||
{
|
||||
return string.IsNullOrEmpty(text);
|
||||
}
|
||||
|
||||
private static bool TextIsNotContainingTermToBeHighlighted(string text, string termToBeHighlighted)
|
||||
{
|
||||
if (text == null || termToBeHighlighted == null)
|
||||
return true;
|
||||
return text.Contains(termToBeHighlighted, StringComparison.OrdinalIgnoreCase) == false;
|
||||
}
|
||||
|
||||
private static void AddPartToTextBlockAndHighlightIfNecessary(TextBlock textBlock, string termToBeHighlighted, string textPart)
|
||||
{
|
||||
if (textPart.Equals(termToBeHighlighted, StringComparison.OrdinalIgnoreCase))
|
||||
AddHighlightedPartToTextBlock(textBlock, textPart);
|
||||
else
|
||||
AddPartToTextBlock(textBlock, textPart);
|
||||
}
|
||||
|
||||
private static void AddPartToTextBlock(TextBlock textBlock, string part)
|
||||
{
|
||||
textBlock.Inlines.Add(new Run {Text = part});
|
||||
}
|
||||
|
||||
private static void AddHighlightedPartToTextBlock(TextBlock textBlock, string part)
|
||||
{
|
||||
Color? foreground = GetHighlightForeground(textBlock);
|
||||
Color? background = GetHighlightBackground(textBlock);
|
||||
|
||||
if (background == null)
|
||||
{
|
||||
Run run = new() {Text = part, FontWeight = FontWeights.ExtraBold};
|
||||
if (foreground != null)
|
||||
run.Foreground = new SolidColorBrush(foreground.Value);
|
||||
textBlock.Inlines.Add(run);
|
||||
return;
|
||||
}
|
||||
|
||||
Border border = new()
|
||||
{
|
||||
Background = new SolidColorBrush(background.Value),
|
||||
BorderThickness = new Thickness(0),
|
||||
CornerRadius = new CornerRadius(2),
|
||||
Child = new TextBlock {Text = part, FontWeight = FontWeights.Bold},
|
||||
Padding = new Thickness(1),
|
||||
Margin = new Thickness(-1, -5, -1, -5)
|
||||
};
|
||||
if (foreground != null)
|
||||
((TextBlock) border.Child).Foreground = new SolidColorBrush(foreground.Value);
|
||||
textBlock.Inlines.Add(border);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Artemis.VisualScripting.Converters
|
||||
{
|
||||
internal class CenterTranslateConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not double doubleValue)
|
||||
return value;
|
||||
|
||||
return doubleValue / 2 * -1;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not double doubleValue)
|
||||
return value;
|
||||
|
||||
return doubleValue * -1 * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.Globalization;
|
||||
using Artemis.Core;
|
||||
using Avalonia.Data.Converters;
|
||||
|
||||
namespace Artemis.VisualScripting.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// Converts input into <see cref="Numeric" />.
|
||||
/// </summary>
|
||||
public class NumericConverter : IValueConverter
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not Numeric numeric)
|
||||
return value;
|
||||
|
||||
return Numeric.IsTypeCompatible(targetType) ? numeric.ToType(targetType, NumberFormatInfo.InvariantInfo) : value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
return new Numeric(value);
|
||||
}
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.VisualScripting.Editor.Controls.Wrapper;
|
||||
|
||||
namespace Artemis.VisualScripting.Editor.Controls
|
||||
{
|
||||
[TemplatePart(Name = PART_PATH, Type = typeof(Path))]
|
||||
public class VisualScriptCablePresenter : Control
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const string PART_PATH = "PART_Path";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
private Path _path;
|
||||
private Border _valueBorder;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dependency Properties
|
||||
|
||||
public static readonly DependencyProperty CableProperty = DependencyProperty.Register(
|
||||
"Cable", typeof(VisualScriptCable), typeof(VisualScriptCablePresenter), new PropertyMetadata(default(VisualScriptCable), CableChanged));
|
||||
|
||||
public VisualScriptCable Cable
|
||||
{
|
||||
get => (VisualScriptCable) GetValue(CableProperty);
|
||||
set => SetValue(CableProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ThicknessProperty = DependencyProperty.Register(
|
||||
"Thickness", typeof(double), typeof(VisualScriptCablePresenter), new PropertyMetadata(default(double)));
|
||||
|
||||
public double Thickness
|
||||
{
|
||||
get => (double) GetValue(ThicknessProperty);
|
||||
set => SetValue(ThicknessProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ValuePositionProperty = DependencyProperty.Register(
|
||||
"ValuePosition", typeof(Point), typeof(VisualScriptCablePresenter), new PropertyMetadata(default(Point)));
|
||||
|
||||
public Point ValuePosition
|
||||
{
|
||||
get => (Point) GetValue(ValuePositionProperty);
|
||||
set => SetValue(ValuePositionProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AlwaysShowValuesProperty = DependencyProperty.Register(
|
||||
"AlwaysShowValues", typeof(bool), typeof(VisualScriptCablePresenter), new PropertyMetadata(default(bool), AlwaysShowValuesChanged));
|
||||
|
||||
public bool AlwaysShowValues
|
||||
{
|
||||
get => (bool) GetValue(AlwaysShowValuesProperty);
|
||||
set => SetValue(AlwaysShowValuesProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
_path = GetTemplateChild(PART_PATH) as Path ?? throw new NullReferenceException($"The Path '{PART_PATH}' is missing.");
|
||||
_valueBorder = GetTemplateChild("PART_ValueDisplay") as Border ?? throw new NullReferenceException("The Border 'PART_ValueDisplay' is missing.");
|
||||
|
||||
_path.MouseEnter += (_, _) => UpdateValueVisibility();
|
||||
_path.MouseLeave += (_, _) => UpdateValueVisibility();
|
||||
_valueBorder.MouseEnter += (_, _) => UpdateValueVisibility();
|
||||
_valueBorder.MouseLeave += (_, _) => UpdateValueVisibility();
|
||||
Unloaded += OnUnloaded;
|
||||
|
||||
UpdateValueVisibility();
|
||||
}
|
||||
|
||||
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (Cable?.From != null)
|
||||
Cable.From.PropertyChanged -= OnPinPropertyChanged;
|
||||
if (Cable?.To != null)
|
||||
Cable.To.PropertyChanged -= OnPinPropertyChanged;
|
||||
}
|
||||
|
||||
private void OnPathMouseDown(object sender, MouseButtonEventArgs args)
|
||||
{
|
||||
if (args.ChangedButton == MouseButton.Left && args.LeftButton == MouseButtonState.Pressed && args.ClickCount == 2)
|
||||
{
|
||||
//TODO DarthAffe 17.06.2021: Should we add rerouting?
|
||||
//AddRerouteNode();
|
||||
}
|
||||
else if (args.ChangedButton == MouseButton.Middle)
|
||||
{
|
||||
Cable.Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private static void CableChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (d is not VisualScriptCablePresenter presenter) return;
|
||||
|
||||
presenter.CableChanged(args);
|
||||
}
|
||||
|
||||
private void CableChanged(DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (args.OldValue is VisualScriptCable oldCable)
|
||||
{
|
||||
oldCable.From.PropertyChanged -= OnPinPropertyChanged;
|
||||
oldCable.To.PropertyChanged -= OnPinPropertyChanged;
|
||||
}
|
||||
|
||||
if (args.NewValue is VisualScriptCable newCable)
|
||||
{
|
||||
newCable.From.PropertyChanged += OnPinPropertyChanged;
|
||||
newCable.To.PropertyChanged += OnPinPropertyChanged;
|
||||
}
|
||||
|
||||
UpdateBorderBrush();
|
||||
UpdateValuePosition();
|
||||
}
|
||||
|
||||
private static void AlwaysShowValuesChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (d is not VisualScriptCablePresenter presenter) return;
|
||||
|
||||
presenter.UpdateValueVisibility();
|
||||
}
|
||||
|
||||
private void UpdateValueVisibility()
|
||||
{
|
||||
if (_valueBorder == null)
|
||||
return;
|
||||
|
||||
if (AlwaysShowValues && Cable.From.Connections.LastOrDefault() == Cable)
|
||||
_valueBorder.Visibility = Visibility.Visible;
|
||||
else if (_valueBorder.IsMouseOver || _path.IsMouseOver)
|
||||
_valueBorder.Visibility = Visibility.Visible;
|
||||
else
|
||||
_valueBorder.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private void OnPinPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(VisualScriptPin.AbsolutePosition))
|
||||
UpdateValuePosition();
|
||||
}
|
||||
|
||||
private void UpdateBorderBrush()
|
||||
{
|
||||
(Color color, Color _) = TypeUtilities.GetTypeColors(Cable.From.Pin.Type);
|
||||
BorderBrush = new SolidColorBrush(color);
|
||||
}
|
||||
|
||||
private void UpdateValuePosition()
|
||||
{
|
||||
if (Cable.From == null || Cable.To == null)
|
||||
return;
|
||||
|
||||
ValuePosition = new Point(
|
||||
Cable.From.AbsolutePosition.X + (Cable.To.AbsolutePosition.X - Cable.From.AbsolutePosition.X) / 2,
|
||||
Cable.From.AbsolutePosition.Y + (Cable.To.AbsolutePosition.Y - Cable.From.AbsolutePosition.Y) / 2
|
||||
);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using Artemis.Core;
|
||||
|
||||
namespace Artemis.VisualScripting.Editor.Controls
|
||||
{
|
||||
public class VisualScriptEditor : Control
|
||||
{
|
||||
#region Dependency Properties
|
||||
|
||||
public static readonly DependencyProperty ScriptProperty = DependencyProperty.Register(
|
||||
"Script", typeof(INodeScript), typeof(VisualScriptEditor), new PropertyMetadata(default(INodeScript)));
|
||||
|
||||
public INodeScript Script
|
||||
{
|
||||
get => (INodeScript)GetValue(ScriptProperty);
|
||||
set => SetValue(ScriptProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AvailableNodesProperty = DependencyProperty.Register(
|
||||
"AvailableNodes", typeof(IEnumerable<NodeData>), typeof(VisualScriptEditor), new PropertyMetadata(default(IEnumerable<NodeData>)));
|
||||
|
||||
public IEnumerable<NodeData> AvailableNodes
|
||||
{
|
||||
get => (IEnumerable<NodeData>)GetValue(AvailableNodesProperty);
|
||||
set => SetValue(AvailableNodesProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AlwaysShowValuesProperty = DependencyProperty.Register(
|
||||
"AlwaysShowValues", typeof(bool), typeof(VisualScriptEditor), new PropertyMetadata(default(bool)));
|
||||
|
||||
public bool AlwaysShowValues
|
||||
{
|
||||
get => (bool)GetValue(AlwaysShowValuesProperty);
|
||||
set => SetValue(AlwaysShowValuesProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
using Artemis.Core;
|
||||
using Artemis.VisualScripting.Editor.Controls.Wrapper;
|
||||
|
||||
namespace Artemis.VisualScripting.Editor.Controls
|
||||
{
|
||||
[TemplatePart(Name = PART_SEARCHBOX, Type = typeof(TextBox))]
|
||||
[TemplatePart(Name = PART_CONTENT, Type = typeof(ListBox))]
|
||||
public class VisualScriptNodeCreationBox : Control
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const string PART_SEARCHBOX = "PART_SearchBox";
|
||||
private const string PART_CONTENT = "PART_Content";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
private TextBox _searchBox;
|
||||
private ListBox _contentList;
|
||||
|
||||
private CollectionViewSource _collectionViewSource;
|
||||
private ICollectionView _contentView;
|
||||
|
||||
#endregion
|
||||
|
||||
#region DependencyProperties
|
||||
|
||||
public static readonly DependencyProperty AvailableNodesProperty = DependencyProperty.Register(
|
||||
"AvailableNodes", typeof(IEnumerable), typeof(VisualScriptNodeCreationBox), new PropertyMetadata(default(IEnumerable), OnItemsSourceChanged));
|
||||
|
||||
public IEnumerable AvailableNodes
|
||||
{
|
||||
get => (IEnumerable) GetValue(AvailableNodesProperty);
|
||||
set => SetValue(AvailableNodesProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SourcePinProperty = DependencyProperty.Register(
|
||||
"SourcePin", typeof(VisualScriptPin), typeof(VisualScriptNodeCreationBox), new PropertyMetadata(default(VisualScriptPin), OnSourcePinChanged));
|
||||
|
||||
public VisualScriptPin SourcePin
|
||||
{
|
||||
get => (VisualScriptPin) GetValue(SourcePinProperty);
|
||||
set => SetValue(SourcePinProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CreateNodeCommandProperty = DependencyProperty.Register(
|
||||
"CreateNodeCommand", typeof(ICommand), typeof(VisualScriptNodeCreationBox), new PropertyMetadata(default(ICommand)));
|
||||
|
||||
public ICommand CreateNodeCommand
|
||||
{
|
||||
get => (ICommand) GetValue(CreateNodeCommandProperty);
|
||||
set => SetValue(CreateNodeCommandProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SearchInputProperty = DependencyProperty.Register(
|
||||
"SearchInput", typeof(string), typeof(VisualScriptNodeCreationBox), new PropertyMetadata(default(string), OnSearchInputChanged));
|
||||
|
||||
public string SearchInput
|
||||
{
|
||||
get => (string) GetValue(SearchInputProperty);
|
||||
set => SetValue(SearchInputProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
_searchBox = GetTemplateChild(PART_SEARCHBOX) as TextBox ?? throw new NullReferenceException($"The Element '{PART_SEARCHBOX}' is missing.");
|
||||
_contentList = GetTemplateChild(PART_CONTENT) as ListBox ?? throw new NullReferenceException($"The Element '{PART_CONTENT}' is missing.");
|
||||
|
||||
_contentList.IsSynchronizedWithCurrentItem = false;
|
||||
_contentList.SelectionChanged += OnContentListSelectionChanged;
|
||||
_contentList.SelectionMode = SelectionMode.Single;
|
||||
IsVisibleChanged += OnIsVisibleChanged;
|
||||
|
||||
_searchBox.Focus();
|
||||
_contentView?.Refresh();
|
||||
ItemsSourceChanged();
|
||||
}
|
||||
|
||||
private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.NewValue is not true)
|
||||
return;
|
||||
|
||||
_searchBox.Focus();
|
||||
_searchBox.SelectionStart = 0;
|
||||
_searchBox.SelectionLength = _searchBox.Text.Length;
|
||||
}
|
||||
|
||||
private void OnContentListSelectionChanged(object sender, SelectionChangedEventArgs args)
|
||||
{
|
||||
if ((args == null) || (_contentList?.SelectedItem == null)) return;
|
||||
|
||||
CreateNodeCommand?.Execute(_contentList.SelectedItem);
|
||||
_contentList.SelectedItem = null;
|
||||
}
|
||||
|
||||
private bool Filter(object o)
|
||||
{
|
||||
if (o is not NodeData nodeData) return false;
|
||||
|
||||
bool searchContains;
|
||||
if (string.IsNullOrWhiteSpace(SearchInput))
|
||||
searchContains = true;
|
||||
else
|
||||
{
|
||||
searchContains = nodeData.Name.Contains(SearchInput, StringComparison.OrdinalIgnoreCase) ||
|
||||
nodeData.Description.Contains(SearchInput, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
if (SourcePin == null || SourcePin.Pin.Type == typeof(object))
|
||||
return searchContains;
|
||||
|
||||
if (SourcePin.Pin.Direction == PinDirection.Input)
|
||||
return nodeData.OutputType != null && searchContains && (nodeData.OutputType == typeof(object) || nodeData.OutputType.IsAssignableTo(SourcePin.Pin.Type));
|
||||
return nodeData.InputType != null && searchContains && (nodeData.InputType == typeof(object) || nodeData.InputType.IsAssignableFrom(SourcePin.Pin.Type));
|
||||
}
|
||||
|
||||
private void ItemsSourceChanged()
|
||||
{
|
||||
if (_contentList == null) return;
|
||||
|
||||
if (AvailableNodes == null)
|
||||
{
|
||||
_contentView = null;
|
||||
_collectionViewSource = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_collectionViewSource = new CollectionViewSource
|
||||
{
|
||||
Source = AvailableNodes,
|
||||
SortDescriptions =
|
||||
{
|
||||
new SortDescription(nameof(NodeData.Category), ListSortDirection.Ascending),
|
||||
new SortDescription(nameof(NodeData.Name), ListSortDirection.Ascending)
|
||||
},
|
||||
GroupDescriptions = {new PropertyGroupDescription(nameof(NodeData.Category))}
|
||||
};
|
||||
_contentView = _collectionViewSource.View;
|
||||
_contentView.Filter += Filter;
|
||||
}
|
||||
|
||||
_contentList.ItemsSource = _contentView;
|
||||
}
|
||||
|
||||
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs args) => (d as VisualScriptNodeCreationBox)?.ItemsSourceChanged();
|
||||
|
||||
private static void OnSourcePinChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => (d as VisualScriptNodeCreationBox)?._contentView.Refresh();
|
||||
|
||||
private static void OnSearchInputChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => (d as VisualScriptNodeCreationBox)?._contentView.Refresh();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using Artemis.Core;
|
||||
using Artemis.VisualScripting.Editor.Controls.Wrapper;
|
||||
|
||||
namespace Artemis.VisualScripting.Editor.Controls
|
||||
{
|
||||
public class VisualScriptNodePresenter : Control
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private bool _isDragging;
|
||||
private bool _isDragged;
|
||||
private bool _isDeselected;
|
||||
private Point _dragStartPosition;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dependency Properties
|
||||
|
||||
public static readonly DependencyProperty NodeProperty = DependencyProperty.Register(
|
||||
"Node", typeof(VisualScriptNode), typeof(VisualScriptNodePresenter), new PropertyMetadata(default(VisualScriptNode), NodePropertyChangedCallback));
|
||||
|
||||
public VisualScriptNode Node
|
||||
{
|
||||
get => (VisualScriptNode) GetValue(NodeProperty);
|
||||
set => SetValue(NodeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CustomViewModelProperty = DependencyProperty.Register(
|
||||
"CustomViewModel", typeof(ICustomNodeViewModel), typeof(VisualScriptNodePresenter), new PropertyMetadata(null));
|
||||
|
||||
public ICustomNodeViewModel CustomViewModel
|
||||
{
|
||||
get => (ICustomNodeViewModel) GetValue(CustomViewModelProperty);
|
||||
set => SetValue(CustomViewModelProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TitleBrushProperty = DependencyProperty.Register(
|
||||
"TitleBrush", typeof(Brush), typeof(VisualScriptNodePresenter), new PropertyMetadata(default(Brush)));
|
||||
|
||||
public Brush TitleBrush
|
||||
{
|
||||
get => (Brush) GetValue(TitleBrushProperty);
|
||||
set => SetValue(TitleBrushProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public VisualScriptNodePresenter()
|
||||
{
|
||||
Loaded += OnLoaded;
|
||||
Unloaded += OnUnloaded;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
protected override Size MeasureOverride(Size constraint)
|
||||
{
|
||||
int SnapToGridSize(int value)
|
||||
{
|
||||
int mod = value % Node.Script.GridSize;
|
||||
return mod switch
|
||||
{
|
||||
< 0 => Node.Script.GridSize,
|
||||
> 0 => value + (Node.Script.GridSize - mod),
|
||||
_ => value
|
||||
};
|
||||
}
|
||||
|
||||
Size neededSize = base.MeasureOverride(constraint);
|
||||
int width = (int) Math.Ceiling(neededSize.Width);
|
||||
int height = (int) Math.Ceiling(neededSize.Height);
|
||||
|
||||
return new Size(SnapToGridSize(width), SnapToGridSize(height));
|
||||
}
|
||||
|
||||
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs args)
|
||||
{
|
||||
base.OnMouseLeftButtonDown(args);
|
||||
|
||||
_isDragged = false;
|
||||
_isDragging = true;
|
||||
_isDeselected = false;
|
||||
|
||||
bool isShiftDown = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
|
||||
if (!Node.IsSelected)
|
||||
Node.Select(isShiftDown);
|
||||
else if (isShiftDown)
|
||||
{
|
||||
_isDeselected = true;
|
||||
Node.Deselect(true);
|
||||
}
|
||||
|
||||
Node.DragStart();
|
||||
|
||||
_dragStartPosition = PointToScreen(args.GetPosition(this));
|
||||
|
||||
CaptureMouse();
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs args)
|
||||
{
|
||||
base.OnMouseLeftButtonUp(args);
|
||||
|
||||
if (_isDragging)
|
||||
{
|
||||
_isDragging = false;
|
||||
Node.DragEnd();
|
||||
|
||||
ReleaseMouseCapture();
|
||||
}
|
||||
|
||||
if (!_isDragged && !_isDeselected)
|
||||
Node.Select(Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift));
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseEventArgs args)
|
||||
{
|
||||
base.OnMouseMove(args);
|
||||
|
||||
if (!_isDragging) return;
|
||||
|
||||
Point mousePosition = PointToScreen(args.GetPosition(this));
|
||||
Vector offset = mousePosition - _dragStartPosition;
|
||||
|
||||
if (args.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
_dragStartPosition = mousePosition;
|
||||
Node.DragMove(offset.X, offset.Y);
|
||||
|
||||
if ((offset.X != 0) && (offset.Y != 0))
|
||||
_isDragged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_isDragging = false;
|
||||
Node.DragEnd();
|
||||
ReleaseMouseCapture();
|
||||
}
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void GetCustomViewModel()
|
||||
{
|
||||
// CustomViewModel?.OnDeactivate();
|
||||
|
||||
if (Node?.Node is Node customViewModelNode)
|
||||
{
|
||||
CustomViewModel = customViewModelNode.GetCustomViewModel((NodeScript) Node.Script.Script);
|
||||
// CustomViewModel?.OnActivate();
|
||||
}
|
||||
else
|
||||
CustomViewModel = null;
|
||||
}
|
||||
|
||||
private static void NodePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is VisualScriptNodePresenter presenter)
|
||||
presenter.GetCustomViewModel();
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (CustomViewModel != null)
|
||||
CustomViewModel.NodeModified += CustomViewModelOnNodeModified;
|
||||
}
|
||||
|
||||
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (CustomViewModel != null)
|
||||
{
|
||||
CustomViewModel.NodeModified -= CustomViewModelOnNodeModified;
|
||||
// CustomViewModel.OnDeactivate();
|
||||
}
|
||||
|
||||
CustomViewModel = null;
|
||||
}
|
||||
|
||||
private void CustomViewModelOnNodeModified(object? sender, EventArgs e)
|
||||
{
|
||||
Node.Script.OnScriptUpdated();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.VisualScripting.Editor.Controls.Wrapper;
|
||||
|
||||
namespace Artemis.VisualScripting.Editor.Controls
|
||||
{
|
||||
[TemplatePart(Name = PART_DOT, Type = typeof(FrameworkElement))]
|
||||
public class VisualScriptPinPresenter : Control
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const string PART_DOT = "PART_Dot";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
private VisualScriptNodePresenter _nodePresenter;
|
||||
private FrameworkElement _dot;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dependency Properties
|
||||
|
||||
public static readonly DependencyProperty PinProperty = DependencyProperty.Register(
|
||||
"Pin", typeof(VisualScriptPin), typeof(VisualScriptPinPresenter), new PropertyMetadata(default(VisualScriptPin), PinChanged));
|
||||
|
||||
public VisualScriptPin Pin
|
||||
{
|
||||
get => (VisualScriptPin)GetValue(PinProperty);
|
||||
set => SetValue(PinProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public VisualScriptPinPresenter()
|
||||
{
|
||||
Loaded += OnLoaded;
|
||||
Unloaded += OnUnloaded;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs args)
|
||||
{
|
||||
DependencyObject parent = this;
|
||||
while ((parent = VisualTreeHelper.GetParent(parent)) != null)
|
||||
{
|
||||
if (parent is VisualScriptNodePresenter nodePresenter)
|
||||
{
|
||||
_nodePresenter = nodePresenter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LayoutUpdated += OnLayoutUpdated;
|
||||
|
||||
UpdateAbsoluteLocation();
|
||||
}
|
||||
|
||||
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
LayoutUpdated -= OnLayoutUpdated;
|
||||
if (Pin != null)
|
||||
Pin.Node.Node.PropertyChanged -= OnNodePropertyChanged;
|
||||
|
||||
_nodePresenter = null;
|
||||
}
|
||||
|
||||
private void OnNodePropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
UpdateAbsoluteLocation();
|
||||
}
|
||||
|
||||
private void OnLayoutUpdated(object sender, EventArgs args)
|
||||
{
|
||||
_dot = GetTemplateChild(PART_DOT) as FrameworkElement ?? throw new NullReferenceException($"The Element '{PART_DOT}' is missing.");
|
||||
|
||||
_dot.AllowDrop = true;
|
||||
|
||||
_dot.MouseDown += OnDotMouseDown;
|
||||
_dot.MouseMove += OnDotMouseMove;
|
||||
_dot.Drop += OnDotDrop;
|
||||
_dot.DragEnter += OnDotDrag;
|
||||
_dot.DragOver += OnDotDrag;
|
||||
|
||||
UpdateAbsoluteLocation();
|
||||
}
|
||||
|
||||
private static void PinChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (d is not VisualScriptPinPresenter presenter) return;
|
||||
|
||||
presenter.PinChanged(args);
|
||||
}
|
||||
|
||||
private void PinChanged(DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (args.OldValue is VisualScriptPin oldPin)
|
||||
oldPin.Node.Node.PropertyChanged -= OnNodePropertyChanged;
|
||||
|
||||
if (args.NewValue is VisualScriptPin newPin)
|
||||
newPin.Node.Node.PropertyChanged += OnNodePropertyChanged;
|
||||
|
||||
UpdateBrushes();
|
||||
UpdateAbsoluteLocation();
|
||||
}
|
||||
|
||||
private void UpdateBrushes()
|
||||
{
|
||||
(Color border, Color background) = TypeUtilities.GetTypeColors(Pin.Pin.Type);
|
||||
Background = new SolidColorBrush(background);
|
||||
BorderBrush = new SolidColorBrush(border);
|
||||
}
|
||||
|
||||
private void UpdateAbsoluteLocation()
|
||||
{
|
||||
if ((Pin == null) || (_nodePresenter == null)) return;
|
||||
|
||||
try
|
||||
{
|
||||
double circleRadius = ActualHeight / 2.0;
|
||||
double xOffset = Pin.Pin.Direction == PinDirection.Input ? circleRadius : ActualWidth - circleRadius;
|
||||
Point relativePosition = this.TransformToVisual(_nodePresenter).Transform(new Point(xOffset, circleRadius));
|
||||
Pin.AbsolutePosition = new Point(Pin.Node.X + relativePosition.X, Pin.Node.Y + relativePosition.Y);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Pin.AbsolutePosition = new Point(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDotMouseDown(object sender, MouseButtonEventArgs args)
|
||||
{
|
||||
if (args.ChangedButton == MouseButton.Middle)
|
||||
Pin.DisconnectAll();
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnDotMouseMove(object sender, MouseEventArgs args)
|
||||
{
|
||||
if (args.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
Pin.SetConnecting(true);
|
||||
DragDrop.DoDragDrop(this, Pin, DragDropEffects.Link);
|
||||
Pin.SetConnecting(false);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDotDrag(object sender, DragEventArgs args)
|
||||
{
|
||||
if (!args.Data.GetDataPresent(typeof(VisualScriptPin)))
|
||||
args.Effects = DragDropEffects.None;
|
||||
else
|
||||
{
|
||||
VisualScriptPin sourcePin = (VisualScriptPin)args.Data.GetData(typeof(VisualScriptPin));
|
||||
if (sourcePin == null)
|
||||
args.Effects = DragDropEffects.None;
|
||||
else
|
||||
args.Effects = ((sourcePin.Pin.Direction != Pin.Pin.Direction) && (sourcePin.Pin.Node != Pin.Pin.Node) && IsTypeCompatible(sourcePin.Pin.Type)) ? DragDropEffects.Link : DragDropEffects.None;
|
||||
}
|
||||
|
||||
if (args.Effects == DragDropEffects.None)
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnDotDrop(object sender, DragEventArgs args)
|
||||
{
|
||||
if (!args.Data.GetDataPresent(typeof(VisualScriptPin))) return;
|
||||
|
||||
VisualScriptPin sourcePin = (VisualScriptPin)args.Data.GetData(typeof(VisualScriptPin));
|
||||
if ((sourcePin == null) || !IsTypeCompatible(sourcePin.Pin.Type)) return;
|
||||
|
||||
try { new VisualScriptCable(Pin, sourcePin); } catch { /**/ }
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private bool IsTypeCompatible(Type type) => (Pin.Pin.Type == type)
|
||||
|| (Pin.Pin.Type == typeof(Enum) && type.IsEnum)
|
||||
|| ((Pin.Pin.Direction == PinDirection.Input) && (Pin.Pin.Type == typeof(object)))
|
||||
|| ((Pin.Pin.Direction == PinDirection.Output) && (type == typeof(object)));
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,624 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
using Artemis.Core;
|
||||
using Artemis.VisualScripting.Editor.Controls.Wrapper;
|
||||
using Artemis.VisualScripting.ViewModel;
|
||||
using VisualScript = Artemis.VisualScripting.Editor.Controls.Wrapper.VisualScript;
|
||||
|
||||
namespace Artemis.VisualScripting.Editor.Controls
|
||||
{
|
||||
[TemplatePart(Name = PART_CANVAS, Type = typeof(Canvas))]
|
||||
[TemplatePart(Name = PART_NODELIST, Type = typeof(ItemsControl))]
|
||||
[TemplatePart(Name = PART_CABLELIST, Type = typeof(ItemsControl))]
|
||||
[TemplatePart(Name = PART_SELECTION_BORDER, Type = typeof(Border))]
|
||||
[TemplatePart(Name = PART_CREATION_BOX_PARENT, Type = typeof(Panel))]
|
||||
public class VisualScriptPresenter : Control
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const string PART_CANVAS = "PART_Canvas";
|
||||
private const string PART_NODELIST = "PART_NodeList";
|
||||
private const string PART_CABLELIST = "PART_CableList";
|
||||
private const string PART_SELECTION_BORDER = "PART_SelectionBorder";
|
||||
private const string PART_CREATION_BOX_PARENT = "PART_CreationBoxParent";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
private bool _fitPending = false;
|
||||
private Canvas _canvas;
|
||||
private ItemsControl _nodeList;
|
||||
private ItemsControl _cableList;
|
||||
private Border _selectionBorder;
|
||||
private TranslateTransform _canvasViewPortTransform;
|
||||
private ScaleTransform _canvasViewPortScale;
|
||||
private Panel _creationBoxParent;
|
||||
|
||||
private Vector _viewportCenter = new(0, 0);
|
||||
|
||||
private bool _dragCanvas = false;
|
||||
private Point _dragCanvasStartLocation;
|
||||
private Vector _dragCanvasStartOffset;
|
||||
private bool _movedDuringDrag = false;
|
||||
|
||||
private bool _boxSelect = false;
|
||||
private Point _boxSelectStartPoint;
|
||||
|
||||
private Point _lastRightClickLocation;
|
||||
|
||||
internal VisualScript VisualScript { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dependency Properties
|
||||
|
||||
public static readonly DependencyProperty ScriptProperty = DependencyProperty.Register(
|
||||
"Script", typeof(INodeScript), typeof(VisualScriptPresenter), new PropertyMetadata(default(INodeScript), ScriptChanged));
|
||||
|
||||
public INodeScript Script
|
||||
{
|
||||
get => (INodeScript) GetValue(ScriptProperty);
|
||||
set => SetValue(ScriptProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ScaleProperty = DependencyProperty.Register(
|
||||
"Scale", typeof(double), typeof(VisualScriptPresenter), new PropertyMetadata(1.0, ScaleChanged));
|
||||
|
||||
public double Scale
|
||||
{
|
||||
get => (double) GetValue(ScaleProperty);
|
||||
set => SetValue(ScaleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MinScaleProperty = DependencyProperty.Register(
|
||||
"MinScale", typeof(double), typeof(VisualScriptPresenter), new PropertyMetadata(0.15));
|
||||
|
||||
public double MinScale
|
||||
{
|
||||
get => (double) GetValue(MinScaleProperty);
|
||||
set => SetValue(MinScaleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaxScaleProperty = DependencyProperty.Register(
|
||||
"MaxScale", typeof(double), typeof(VisualScriptPresenter), new PropertyMetadata(1.0));
|
||||
|
||||
public double MaxScale
|
||||
{
|
||||
get => (double) GetValue(MaxScaleProperty);
|
||||
set => SetValue(MaxScaleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ScaleFactorProperty = DependencyProperty.Register(
|
||||
"ScaleFactor", typeof(double), typeof(VisualScriptPresenter), new PropertyMetadata(1.3));
|
||||
|
||||
public double ScaleFactor
|
||||
{
|
||||
get => (double) GetValue(ScaleFactorProperty);
|
||||
set => SetValue(ScaleFactorProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AvailableNodesProperty = DependencyProperty.Register(
|
||||
"AvailableNodes", typeof(IEnumerable<NodeData>), typeof(VisualScriptPresenter), new PropertyMetadata(default(IEnumerable<NodeData>)));
|
||||
|
||||
public IEnumerable<NodeData> AvailableNodes
|
||||
{
|
||||
get => (IEnumerable<NodeData>) GetValue(AvailableNodesProperty);
|
||||
set => SetValue(AvailableNodesProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AlwaysShowValuesProperty = DependencyProperty.Register(
|
||||
"AlwaysShowValues", typeof(bool), typeof(VisualScriptPresenter), new PropertyMetadata(default(bool)));
|
||||
|
||||
public bool AlwaysShowValues
|
||||
{
|
||||
get => (bool) GetValue(AlwaysShowValuesProperty);
|
||||
set => SetValue(AlwaysShowValuesProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SourcePinProperty = DependencyProperty.Register(
|
||||
"SourcePin", typeof(VisualScriptPin), typeof(VisualScriptPresenter), new PropertyMetadata(default(VisualScriptPin)));
|
||||
|
||||
public VisualScriptPin SourcePin
|
||||
{
|
||||
get => (VisualScriptPin) GetValue(SourcePinProperty);
|
||||
set => SetValue(SourcePinProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CreateNodeCommandProperty = DependencyProperty.Register(
|
||||
"CreateNodeCommand", typeof(ICommand), typeof(VisualScriptPresenter), new PropertyMetadata(default(ICommand)));
|
||||
|
||||
public ICommand CreateNodeCommand
|
||||
{
|
||||
get => (ICommand) GetValue(CreateNodeCommandProperty);
|
||||
private set => SetValue(CreateNodeCommandProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty GridSizeProperty = DependencyProperty.Register(
|
||||
"GridSize", typeof(int), typeof(VisualScriptPresenter), new PropertyMetadata(24));
|
||||
|
||||
public int GridSize
|
||||
{
|
||||
get => (int) GetValue(GridSizeProperty);
|
||||
set => SetValue(GridSizeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SurfaceSizeProperty = DependencyProperty.Register(
|
||||
"SurfaceSize", typeof(int), typeof(VisualScriptPresenter), new PropertyMetadata(16384));
|
||||
|
||||
public int SurfaceSize
|
||||
{
|
||||
get => (int) GetValue(SurfaceSizeProperty);
|
||||
set => SetValue(SurfaceSizeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AutoFitScriptProperty = DependencyProperty.Register(
|
||||
"AutoFitScript", typeof(bool), typeof(VisualScriptPresenter), new PropertyMetadata(false, AutoFitScriptChanged));
|
||||
|
||||
public bool AutoFitScript
|
||||
{
|
||||
get => (bool) GetValue(AutoFitScriptProperty);
|
||||
set => SetValue(AutoFitScriptProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler ScriptUpdated;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public VisualScriptPresenter()
|
||||
{
|
||||
CreateNodeCommand = new ActionCommand<NodeData>(CreateNode);
|
||||
|
||||
this.SizeChanged += OnSizeChanged;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
_canvas = GetTemplateChild(PART_CANVAS) as Canvas ?? throw new NullReferenceException($"The Canvas '{PART_CANVAS}' is missing.");
|
||||
_selectionBorder = GetTemplateChild(PART_SELECTION_BORDER) as Border ?? throw new NullReferenceException($"The Border '{PART_SELECTION_BORDER}' is missing.");
|
||||
_nodeList = GetTemplateChild(PART_NODELIST) as ItemsControl ?? throw new NullReferenceException($"The ItemsControl '{PART_NODELIST}' is missing.");
|
||||
_cableList = GetTemplateChild(PART_CABLELIST) as ItemsControl ?? throw new NullReferenceException($"The ItemsControl '{PART_CABLELIST}' is missing.");
|
||||
_creationBoxParent = GetTemplateChild(PART_CREATION_BOX_PARENT) as Panel ?? throw new NullReferenceException($"The Panel '{PART_CREATION_BOX_PARENT}' is missing.");
|
||||
|
||||
_canvas.AllowDrop = true;
|
||||
|
||||
_canvas.LayoutTransform = _canvasViewPortScale = new ScaleTransform(MaxScale, MaxScale);
|
||||
_canvas.RenderTransform = _canvasViewPortTransform = new TranslateTransform(0, 0);
|
||||
_canvas.MouseLeftButtonDown += OnCanvasMouseLeftButtonDown;
|
||||
_canvas.MouseLeftButtonUp += OnCanvasMouseLeftButtonUp;
|
||||
_canvas.PreviewMouseRightButtonDown += OnCanvasPreviewMouseRightButtonDown;
|
||||
_canvas.MouseMove += OnCanvasMouseMove;
|
||||
_canvas.MouseWheel += OnCanvasMouseWheel;
|
||||
_canvas.DragOver += OnCanvasDragOver;
|
||||
_canvas.Drop += OnCanvasDrop;
|
||||
_nodeList.ItemsSource = VisualScript?.Nodes;
|
||||
_cableList.ItemsSource = VisualScript?.Cables;
|
||||
}
|
||||
|
||||
private static void AutoFitScriptChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (d is not VisualScriptPresenter scriptPresenter) return;
|
||||
|
||||
if ((args.NewValue as bool?) == true)
|
||||
scriptPresenter.FitScript();
|
||||
}
|
||||
|
||||
private void OnSizeChanged(object sender, SizeChangedEventArgs args)
|
||||
{
|
||||
if (sender is not VisualScriptPresenter scriptPresenter) return;
|
||||
|
||||
if (AutoFitScript)
|
||||
scriptPresenter.FitScript();
|
||||
else
|
||||
scriptPresenter.UpdatePanning();
|
||||
}
|
||||
|
||||
private static void ScriptChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (d is not VisualScriptPresenter scriptPresenter) return;
|
||||
|
||||
scriptPresenter.ScriptChanged(args.NewValue is not NodeScript script ? null : new VisualScript(script, scriptPresenter.SurfaceSize, scriptPresenter.GridSize));
|
||||
}
|
||||
|
||||
private void ScriptChanged(VisualScript newScript)
|
||||
{
|
||||
if (VisualScript != null)
|
||||
{
|
||||
VisualScript.ScriptUpdated -= OnVisualScriptScriptUpdated;
|
||||
VisualScript.PropertyChanged -= OnVisualScriptPropertyChanged;
|
||||
VisualScript.NodeMoved -= OnVisualScriptNodeMoved;
|
||||
VisualScript.NodeCollectionChanged -= OnVisualScriptNodeCollectionChanged;
|
||||
}
|
||||
|
||||
VisualScript = newScript;
|
||||
|
||||
if (VisualScript != null)
|
||||
{
|
||||
VisualScript.ScriptUpdated += OnVisualScriptScriptUpdated;
|
||||
VisualScript.PropertyChanged += OnVisualScriptPropertyChanged;
|
||||
VisualScript.NodeMoved += OnVisualScriptNodeMoved;
|
||||
VisualScript.NodeCollectionChanged += OnVisualScriptNodeCollectionChanged;
|
||||
|
||||
if (_nodeList != null)
|
||||
_nodeList.ItemsSource = VisualScript?.Nodes;
|
||||
|
||||
if (_cableList != null)
|
||||
_cableList.ItemsSource = VisualScript?.Cables;
|
||||
}
|
||||
|
||||
VisualScript?.RecreateCables();
|
||||
|
||||
if (AutoFitScript)
|
||||
FitScript();
|
||||
else
|
||||
CenterAt(new Vector(0, 0));
|
||||
}
|
||||
|
||||
private void OnVisualScriptScriptUpdated(object sender, EventArgs e)
|
||||
{
|
||||
ScriptUpdated?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void OnVisualScriptPropertyChanged(object sender, PropertyChangedEventArgs args)
|
||||
{
|
||||
if (args.PropertyName == nameof(VisualScript.Cables))
|
||||
if (_cableList != null)
|
||||
_cableList.ItemsSource = VisualScript.Cables;
|
||||
}
|
||||
|
||||
private void OnVisualScriptNodeMoved(object sender, EventArgs args)
|
||||
{
|
||||
if (AutoFitScript)
|
||||
FitScript();
|
||||
}
|
||||
|
||||
private void OnVisualScriptNodeCollectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (AutoFitScript)
|
||||
FitScript();
|
||||
}
|
||||
|
||||
private void OnCanvasPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs args)
|
||||
{
|
||||
_lastRightClickLocation = args.GetPosition(_canvas);
|
||||
}
|
||||
|
||||
private void OnCanvasMouseLeftButtonDown(object sender, MouseButtonEventArgs args)
|
||||
{
|
||||
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
||||
{
|
||||
if (AutoFitScript)
|
||||
{
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
_dragCanvas = true;
|
||||
_dragCanvasStartLocation = args.GetPosition(this);
|
||||
_dragCanvasStartOffset = _viewportCenter;
|
||||
|
||||
_movedDuringDrag = false;
|
||||
|
||||
_canvas.CaptureMouse();
|
||||
|
||||
args.Handled = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
VisualScript.DeselectAllNodes();
|
||||
|
||||
_boxSelect = true;
|
||||
_boxSelectStartPoint = args.GetPosition(_canvas);
|
||||
Canvas.SetLeft(_selectionBorder, _boxSelectStartPoint.X);
|
||||
Canvas.SetTop(_selectionBorder, _boxSelectStartPoint.Y);
|
||||
_selectionBorder.Width = 0;
|
||||
_selectionBorder.Height = 0;
|
||||
_selectionBorder.Visibility = Visibility.Visible;
|
||||
_canvas.CaptureMouse();
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnCanvasMouseLeftButtonUp(object sender, MouseButtonEventArgs args)
|
||||
{
|
||||
if (_boxSelect)
|
||||
{
|
||||
_boxSelect = false;
|
||||
_canvas.ReleaseMouseCapture();
|
||||
Mouse.OverrideCursor = null;
|
||||
_selectionBorder.Visibility = Visibility.Hidden;
|
||||
SelectWithinRectangle(new Rect(Canvas.GetLeft(_selectionBorder), Canvas.GetTop(_selectionBorder), _selectionBorder.Width, _selectionBorder.Height));
|
||||
args.Handled = _movedDuringDrag;
|
||||
}
|
||||
|
||||
if (_dragCanvas)
|
||||
{
|
||||
_dragCanvas = false;
|
||||
_canvas.ReleaseMouseCapture();
|
||||
Mouse.OverrideCursor = null;
|
||||
args.Handled = _movedDuringDrag;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCanvasMouseMove(object sender, MouseEventArgs args)
|
||||
{
|
||||
if (_dragCanvas)
|
||||
{
|
||||
if (args.LeftButton == MouseButtonState.Pressed && (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)))
|
||||
{
|
||||
Vector newLocation = _dragCanvasStartOffset - (((args.GetPosition(this) - _dragCanvasStartLocation)) * (1.0 / Scale));
|
||||
CenterAt(newLocation);
|
||||
|
||||
_movedDuringDrag = true;
|
||||
Mouse.OverrideCursor = Cursors.ScrollAll;
|
||||
}
|
||||
else
|
||||
_dragCanvas = false;
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
else if (_boxSelect)
|
||||
{
|
||||
if (args.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
double x = _boxSelectStartPoint.X;
|
||||
double y = _boxSelectStartPoint.Y;
|
||||
Point mousePosition = args.GetPosition(_canvas);
|
||||
|
||||
double rectX = mousePosition.X > x ? x : mousePosition.X;
|
||||
double rectY = mousePosition.Y > y ? y : mousePosition.Y;
|
||||
double rectWidth = Math.Abs(x - mousePosition.X);
|
||||
double rectHeight = Math.Abs(y - mousePosition.Y);
|
||||
|
||||
Canvas.SetLeft(_selectionBorder, rectX);
|
||||
Canvas.SetTop(_selectionBorder, rectY);
|
||||
_selectionBorder.Width = rectWidth;
|
||||
_selectionBorder.Height = rectHeight;
|
||||
}
|
||||
else
|
||||
_boxSelect = false;
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCanvasDragOver(object sender, DragEventArgs args)
|
||||
{
|
||||
if (VisualScript.IsConnecting)
|
||||
VisualScript.OnDragOver(args.GetPosition(_canvas));
|
||||
}
|
||||
|
||||
private void OnCanvasDrop(object sender, DragEventArgs args)
|
||||
{
|
||||
if (!args.Data.GetDataPresent(typeof(VisualScriptPin))) return;
|
||||
|
||||
VisualScriptPin sourcePin = (VisualScriptPin) args.Data.GetData(typeof(VisualScriptPin));
|
||||
if (sourcePin == null) return;
|
||||
|
||||
if (_creationBoxParent.ContextMenu != null)
|
||||
{
|
||||
SourcePin = sourcePin;
|
||||
|
||||
_lastRightClickLocation = args.GetPosition(_canvas);
|
||||
_creationBoxParent.ContextMenu.IsOpen = true;
|
||||
_creationBoxParent.ContextMenu.DataContext = this;
|
||||
|
||||
void ContextMenuOnClosed(object s, RoutedEventArgs e)
|
||||
{
|
||||
SourcePin = null;
|
||||
if (_creationBoxParent.ContextMenu != null)
|
||||
_creationBoxParent.ContextMenu.Closed -= ContextMenuOnClosed;
|
||||
}
|
||||
|
||||
_creationBoxParent.ContextMenu.Closed += ContextMenuOnClosed;
|
||||
}
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnCanvasMouseWheel(object sender, MouseWheelEventArgs args)
|
||||
{
|
||||
if (AutoFitScript)
|
||||
{
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Delta < 0)
|
||||
Scale /= ScaleFactor;
|
||||
else
|
||||
Scale *= ScaleFactor;
|
||||
|
||||
Scale = Clamp(Scale, MinScale, MaxScale);
|
||||
|
||||
UpdatePanning();
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void SelectWithinRectangle(Rect rectangle)
|
||||
{
|
||||
if (Script == null) return;
|
||||
|
||||
VisualScript.DeselectAllNodes();
|
||||
|
||||
for (int i = 0; i < _nodeList.Items.Count; i++)
|
||||
{
|
||||
ContentPresenter nodeControl = (ContentPresenter) _nodeList.ItemContainerGenerator.ContainerFromIndex(i);
|
||||
VisualScriptNode node = (VisualScriptNode) nodeControl.Content;
|
||||
|
||||
double nodeWidth = nodeControl.ActualWidth;
|
||||
double nodeHeight = nodeControl.ActualHeight;
|
||||
|
||||
if (rectangle.IntersectsWith(new Rect(node.X, node.Y, nodeWidth, nodeHeight)))
|
||||
node.Select(true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ScaleChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (d is not VisualScriptPresenter presenter) return;
|
||||
if (presenter.VisualScript == null) return;
|
||||
|
||||
presenter._canvasViewPortScale.ScaleX = presenter.Scale;
|
||||
presenter._canvasViewPortScale.ScaleY = presenter.Scale;
|
||||
|
||||
presenter.VisualScript.NodeDragScale = 1.0 / presenter.Scale;
|
||||
}
|
||||
|
||||
private void FitScript()
|
||||
{
|
||||
if (_fitPending) return;
|
||||
|
||||
_fitPending = true;
|
||||
Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(FitScriptAction));
|
||||
}
|
||||
|
||||
private void FitScriptAction()
|
||||
{
|
||||
_fitPending = false;
|
||||
|
||||
if ((Script == null) || (_nodeList == null)) return;
|
||||
|
||||
double minX = double.MaxValue;
|
||||
double maxX = double.MinValue;
|
||||
double minY = double.MaxValue;
|
||||
double maxY = double.MinValue;
|
||||
for (int i = 0; i < _nodeList.Items.Count; i++)
|
||||
{
|
||||
DependencyObject container = _nodeList.ItemContainerGenerator.ContainerFromIndex(i);
|
||||
VisualScriptNodePresenter nodePresenter = GetChildOfType<VisualScriptNodePresenter>(container);
|
||||
if (nodePresenter != null)
|
||||
{
|
||||
minX = Math.Min(minX, nodePresenter.Node.Node.X);
|
||||
minY = Math.Min(minY, nodePresenter.Node.Node.Y);
|
||||
|
||||
maxX = Math.Max(maxX, nodePresenter.Node.Node.X + nodePresenter.ActualWidth);
|
||||
maxY = Math.Max(maxY, nodePresenter.Node.Node.Y + nodePresenter.ActualHeight);
|
||||
}
|
||||
}
|
||||
|
||||
if (minX >= (double.MaxValue - 1))
|
||||
{
|
||||
Scale = MaxScale;
|
||||
CenterAt(new Vector(0, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
double width = maxX - minX;
|
||||
double height = maxY - minY;
|
||||
|
||||
double scaleX = ActualWidth / width;
|
||||
double scaleY = ActualHeight / height;
|
||||
|
||||
Scale = Clamp(Math.Min(scaleX, scaleY) / 1.05, 0, MaxScale); //DarthAffe 21.08.2021: 5% Border
|
||||
|
||||
CenterAt(new Vector(minX + (width / 2.0), minY + (height / 2.0)));
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateNode(NodeData nodeData)
|
||||
{
|
||||
if (nodeData == null) return;
|
||||
|
||||
INode node = nodeData.CreateNode(Script, null);
|
||||
node.X = _lastRightClickLocation.X - VisualScript.LocationOffset;
|
||||
node.Y = _lastRightClickLocation.Y - VisualScript.LocationOffset;
|
||||
|
||||
if (SourcePin != null)
|
||||
{
|
||||
// Connect to the first matching input or output pin
|
||||
List<IPin> pins = node.Pins.ToList();
|
||||
pins.AddRange(node.PinCollections.SelectMany(c => c));
|
||||
pins = pins.Where(p => p.Type == typeof(object) || p.Type.IsAssignableFrom(SourcePin.Pin.Type)).OrderBy(p => p.Type != typeof(object)).ToList();
|
||||
|
||||
IPin preferredPin = SourcePin.Pin.Direction == PinDirection.Input
|
||||
? pins.FirstOrDefault(p => p.Direction == PinDirection.Output)
|
||||
: pins.FirstOrDefault(p => p.Direction == PinDirection.Input);
|
||||
|
||||
if (preferredPin != null)
|
||||
{
|
||||
preferredPin.ConnectTo(SourcePin.Pin);
|
||||
SourcePin.Pin.ConnectTo(preferredPin);
|
||||
}
|
||||
}
|
||||
|
||||
if (_creationBoxParent.ContextMenu != null)
|
||||
_creationBoxParent.ContextMenu.IsOpen = false;
|
||||
|
||||
Script.AddNode(node);
|
||||
VisualScript.OnScriptUpdated();
|
||||
}
|
||||
|
||||
private void CenterAt(Vector vector)
|
||||
{
|
||||
double halfSurface = (SurfaceSize / 2.0);
|
||||
_viewportCenter = Clamp(vector, new Vector(-halfSurface, -halfSurface), new Vector(halfSurface, halfSurface));
|
||||
UpdatePanning();
|
||||
}
|
||||
|
||||
private void UpdatePanning()
|
||||
{
|
||||
if (_canvasViewPortTransform == null) return;
|
||||
|
||||
double surfaceOffset = (SurfaceSize / 2.0) * Scale;
|
||||
_canvasViewPortTransform.X = (((-_viewportCenter.X * Scale) + (ActualWidth / 2.0))) - surfaceOffset;
|
||||
_canvasViewPortTransform.Y = (((-_viewportCenter.Y * Scale) + (ActualHeight / 2.0))) - surfaceOffset;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static double Clamp(double value, double min, double max)
|
||||
{
|
||||
// ReSharper disable ConvertIfStatementToReturnStatement - I'm not sure why, but inlining this statement reduces performance by ~10%
|
||||
if (value < min) return min;
|
||||
if (value > max) return max;
|
||||
return value;
|
||||
// ReSharper restore ConvertIfStatementToReturnStatement
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static Vector Clamp(Vector value, Vector min, Vector max)
|
||||
{
|
||||
double x = Clamp(value.X, min.X, max.X);
|
||||
double y = Clamp(value.Y, min.Y, max.Y);
|
||||
return new Vector(x, y);
|
||||
}
|
||||
|
||||
public static T GetChildOfType<T>(DependencyObject obj)
|
||||
where T : DependencyObject
|
||||
{
|
||||
if (obj == null) return null;
|
||||
|
||||
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
|
||||
{
|
||||
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
|
||||
|
||||
T result = (child as T) ?? GetChildOfType<T>(child);
|
||||
if (result != null) return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,298 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Events;
|
||||
using Artemis.VisualScripting.Events;
|
||||
using Artemis.VisualScripting.ViewModel;
|
||||
|
||||
namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
||||
{
|
||||
public class VisualScript : AbstractBindable
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private bool _cableRecreationPending = false;
|
||||
|
||||
private readonly HashSet<VisualScriptNode> _selectedNodes = new();
|
||||
private readonly Dictionary<VisualScriptNode, (double X, double Y)> _nodeStartPositions = new();
|
||||
private double _nodeDragAccumulationX;
|
||||
private double _nodeDragAccumulationY;
|
||||
|
||||
public INodeScript Script { get; }
|
||||
|
||||
public int SurfaceSize { get; }
|
||||
public int GridSize { get; }
|
||||
|
||||
private double _nodeDragScale = 1;
|
||||
public double NodeDragScale
|
||||
{
|
||||
get => _nodeDragScale;
|
||||
set => SetProperty(ref _nodeDragScale, value);
|
||||
}
|
||||
|
||||
internal double LocationOffset { get; }
|
||||
|
||||
private VisualScriptPin _isConnectingPin;
|
||||
private VisualScriptPin IsConnectingPin
|
||||
{
|
||||
get => _isConnectingPin;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _isConnectingPin, value))
|
||||
OnPropertyChanged(nameof(IsConnecting));
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Dictionary<INode, VisualScriptNode> _nodeMapping = new();
|
||||
public ObservableCollection<VisualScriptNode> Nodes { get; } = new();
|
||||
|
||||
public IEnumerable<VisualScriptCable> Cables => Nodes.SelectMany(n => n.InputPins.SelectMany(p => p.InternalConnections))
|
||||
.Concat(Nodes.SelectMany(n => n.OutputPins.SelectMany(p => p.InternalConnections)))
|
||||
.Concat(Nodes.SelectMany(n => n.InputPinCollections.SelectMany(p => p.Pins).SelectMany(p => p.InternalConnections)))
|
||||
.Concat(Nodes.SelectMany(n => n.OutputPinCollections.SelectMany(p => p.Pins).SelectMany(p => p.InternalConnections)))
|
||||
.Distinct();
|
||||
|
||||
public bool IsConnecting => IsConnectingPin != null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler NodeMoved;
|
||||
public event EventHandler NodeCollectionChanged;
|
||||
public event EventHandler ScriptUpdated;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public VisualScript(INodeScript script, int surfaceSize, int gridSize)
|
||||
{
|
||||
this.Script = script;
|
||||
this.SurfaceSize = surfaceSize;
|
||||
this.GridSize = gridSize;
|
||||
|
||||
LocationOffset = SurfaceSize / 2.0;
|
||||
|
||||
CollectionChangedEventManager.AddHandler(Nodes, OnNodeCollectionChanged);
|
||||
NodeAddedEventManager.AddHandler(script, OnScriptNodeAdded);
|
||||
NodeRemovedEventManager.AddHandler(script, OnScriptNodeRemoved);
|
||||
|
||||
foreach (INode node in Script.Nodes)
|
||||
InitializeNode(node);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public void DeselectAllNodes(VisualScriptNode except = null)
|
||||
{
|
||||
List<VisualScriptNode> selectedNodes = _selectedNodes.ToList();
|
||||
foreach (VisualScriptNode node in selectedNodes.Where(n => n != except))
|
||||
node.Deselect();
|
||||
}
|
||||
|
||||
private void OnNodeCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
|
||||
{
|
||||
if (args.OldItems != null)
|
||||
UnregisterNodes(args.OldItems.Cast<VisualScriptNode>());
|
||||
|
||||
if (args.NewItems != null)
|
||||
RegisterNodes(args.NewItems.Cast<VisualScriptNode>());
|
||||
}
|
||||
|
||||
private void OnScriptNodeAdded(object sender, SingleValueEventArgs<INode> args)
|
||||
{
|
||||
if (_nodeMapping.ContainsKey(args.Value)) return;
|
||||
|
||||
InitializeNode(args.Value);
|
||||
}
|
||||
|
||||
private void OnScriptNodeRemoved(object sender, SingleValueEventArgs<INode> args)
|
||||
{
|
||||
if (!_nodeMapping.TryGetValue(args.Value, out VisualScriptNode visualScriptNode)) return;
|
||||
|
||||
Nodes.Remove(visualScriptNode);
|
||||
}
|
||||
|
||||
private void InitializeNode(INode node)
|
||||
{
|
||||
VisualScriptNode visualScriptNode = new(this, node);
|
||||
visualScriptNode.SnapNodeToGrid();
|
||||
Nodes.Add(visualScriptNode);
|
||||
}
|
||||
|
||||
private void RegisterNodes(IEnumerable<VisualScriptNode> nodes)
|
||||
{
|
||||
foreach (VisualScriptNode node in nodes)
|
||||
{
|
||||
_nodeMapping.Add(node.Node, node);
|
||||
|
||||
node.IsSelectedChanged += OnNodeIsSelectedChanged;
|
||||
node.DragStarting += OnNodeDragStarting;
|
||||
node.DragEnding += OnNodeDragEnding;
|
||||
node.DragMoving += OnNodeDragMoving;
|
||||
node.PropertyChanged += OnNodePropertyChanged;
|
||||
|
||||
if (node.IsSelected)
|
||||
_selectedNodes.Add(node);
|
||||
}
|
||||
|
||||
NodeCollectionChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void UnregisterNodes(IEnumerable<VisualScriptNode> nodes)
|
||||
{
|
||||
foreach (VisualScriptNode node in nodes)
|
||||
{
|
||||
_nodeMapping.Remove(node.Node);
|
||||
|
||||
node.IsSelectedChanged -= OnNodeIsSelectedChanged;
|
||||
node.DragStarting -= OnNodeDragStarting;
|
||||
node.DragEnding -= OnNodeDragEnding;
|
||||
node.DragMoving -= OnNodeDragMoving;
|
||||
node.PropertyChanged -= OnNodePropertyChanged;
|
||||
|
||||
_selectedNodes.Remove(node);
|
||||
}
|
||||
|
||||
NodeCollectionChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void OnNodePropertyChanged(object sender, PropertyChangedEventArgs args)
|
||||
{
|
||||
if (string.Equals(args.PropertyName, nameof(VisualScriptNode.X), StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(args.PropertyName, nameof(VisualScriptNode.Y), StringComparison.OrdinalIgnoreCase))
|
||||
NodeMoved?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void OnNodeIsSelectedChanged(object sender, VisualScriptNodeIsSelectedChangedEventArgs args)
|
||||
{
|
||||
if (sender is not VisualScriptNode node) return;
|
||||
|
||||
if (args.IsSelected)
|
||||
{
|
||||
if (!args.AlterSelection)
|
||||
DeselectAllNodes(node);
|
||||
|
||||
_selectedNodes.Add(node);
|
||||
}
|
||||
else
|
||||
_selectedNodes.Remove(node);
|
||||
}
|
||||
|
||||
private void OnNodeDragStarting(object sender, EventArgs args)
|
||||
{
|
||||
_nodeDragAccumulationX = 0;
|
||||
_nodeDragAccumulationY = 0;
|
||||
_nodeStartPositions.Clear();
|
||||
|
||||
foreach (VisualScriptNode node in _selectedNodes)
|
||||
_nodeStartPositions.Add(node, (node.X, node.Y));
|
||||
}
|
||||
|
||||
private void OnNodeDragEnding(object sender, EventArgs args)
|
||||
{
|
||||
foreach (VisualScriptNode node in _selectedNodes)
|
||||
node.SnapNodeToGrid();
|
||||
|
||||
OnScriptUpdated();
|
||||
}
|
||||
|
||||
private void OnNodeDragMoving(object sender, VisualScriptNodeDragMovingEventArgs args)
|
||||
{
|
||||
_nodeDragAccumulationX += args.DX * NodeDragScale;
|
||||
_nodeDragAccumulationY += args.DY * NodeDragScale;
|
||||
|
||||
foreach (VisualScriptNode node in _selectedNodes)
|
||||
{
|
||||
node.X = _nodeStartPositions[node].X + _nodeDragAccumulationX;
|
||||
node.Y = _nodeStartPositions[node].Y + _nodeDragAccumulationY;
|
||||
node.SnapNodeToGrid();
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnDragOver(Point position)
|
||||
{
|
||||
if (IsConnectingPin == null) return;
|
||||
|
||||
IsConnectingPin.AbsolutePosition = position;
|
||||
}
|
||||
|
||||
internal void OnIsConnectingPinChanged(VisualScriptPin isConnectingPin)
|
||||
{
|
||||
IsConnectingPin = isConnectingPin;
|
||||
}
|
||||
|
||||
internal void OnPinConnected(PinConnectedEventArgs args)
|
||||
{
|
||||
OnPropertyChanged(nameof(Cables));
|
||||
}
|
||||
|
||||
internal void OnPinDisconnected(PinDisconnectedEventArgs args)
|
||||
{
|
||||
OnPropertyChanged(nameof(Cables));
|
||||
}
|
||||
|
||||
public void RemoveNode(VisualScriptNode node)
|
||||
{
|
||||
Nodes.Remove(node);
|
||||
Script.RemoveNode(node.Node);
|
||||
}
|
||||
|
||||
internal void RequestCableRecreation()
|
||||
{
|
||||
if (_cableRecreationPending) return;
|
||||
|
||||
_cableRecreationPending = true;
|
||||
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(RecreateCables));
|
||||
}
|
||||
|
||||
internal void RecreateCables()
|
||||
{
|
||||
_cableRecreationPending = false;
|
||||
|
||||
Dictionary<IPin, VisualScriptPin> pinMapping = Nodes.SelectMany(n => n.InputPins)
|
||||
.Concat(Nodes.SelectMany(n => n.OutputPins))
|
||||
.Concat(Nodes.SelectMany(n => n.InputPinCollections.SelectMany(p => p.Pins)))
|
||||
.Concat(Nodes.SelectMany(n => n.OutputPinCollections.SelectMany(p => p.Pins)))
|
||||
.ToDictionary(p => p.Pin, p => p);
|
||||
|
||||
foreach (VisualScriptPin pin in pinMapping.Values)
|
||||
pin.InternalConnections.Clear();
|
||||
|
||||
HashSet<IPin> connectedPins = new();
|
||||
foreach (IPin pin in pinMapping.Keys)
|
||||
{
|
||||
foreach (IPin connectedPin in pin.ConnectedTo)
|
||||
if (!connectedPins.Contains(connectedPin))
|
||||
if (pinMapping.TryGetValue(pin, out VisualScriptPin pin1)
|
||||
&& pinMapping.TryGetValue(connectedPin, out VisualScriptPin pin2))
|
||||
{
|
||||
VisualScriptCable cable = new(pin1, pin2, false);
|
||||
pin1.InternalConnections.Add(cable);
|
||||
pin2.InternalConnections.Add(cable);
|
||||
}
|
||||
|
||||
connectedPins.Add(pin);
|
||||
}
|
||||
|
||||
OnPropertyChanged(nameof(Cables));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void OnScriptUpdated()
|
||||
{
|
||||
ScriptUpdated?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
using System;
|
||||
using Artemis.Core;
|
||||
using Artemis.VisualScripting.ViewModel;
|
||||
|
||||
namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
||||
{
|
||||
public class VisualScriptCable : AbstractBindable
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private VisualScriptPin _from;
|
||||
public VisualScriptPin From
|
||||
{
|
||||
get => _from;
|
||||
private set => SetProperty(ref _from, value);
|
||||
}
|
||||
|
||||
private VisualScriptPin _to;
|
||||
public VisualScriptPin To
|
||||
{
|
||||
get => _to;
|
||||
private set => SetProperty(ref _to, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public VisualScriptCable(VisualScriptPin pin1, VisualScriptPin pin2)
|
||||
: this(pin1, pin2, true)
|
||||
{ }
|
||||
|
||||
internal VisualScriptCable(VisualScriptPin pin1, VisualScriptPin pin2, bool connect)
|
||||
{
|
||||
if ((pin1.Pin.Direction == PinDirection.Input) && (pin2.Pin.Direction == PinDirection.Input))
|
||||
throw new ArgumentException("Can't connect two input pins.");
|
||||
|
||||
if ((pin1.Pin.Direction == PinDirection.Output) && (pin2.Pin.Direction == PinDirection.Output))
|
||||
throw new ArgumentException("Can't connect two output pins.");
|
||||
|
||||
From = pin1.Pin.Direction == PinDirection.Output ? pin1 : pin2;
|
||||
To = pin1.Pin.Direction == PinDirection.Input ? pin1 : pin2;
|
||||
|
||||
if (connect)
|
||||
{
|
||||
From.ConnectTo(this);
|
||||
To.ConnectTo(this);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
internal void Disconnect()
|
||||
{
|
||||
From?.Disconnect(this);
|
||||
To?.Disconnect(this);
|
||||
|
||||
From = null;
|
||||
To = null;
|
||||
}
|
||||
|
||||
internal IPin GetConnectedPin(IPin pin)
|
||||
{
|
||||
if (From.Pin == pin) return To.Pin;
|
||||
if (To.Pin == pin) return From.Pin;
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,290 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.VisualScripting.Events;
|
||||
using Artemis.VisualScripting.ViewModel;
|
||||
|
||||
namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
||||
{
|
||||
public class VisualScriptNode : AbstractBindable
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private readonly Dictionary<IPin, VisualScriptPin> _pinMapping = new();
|
||||
|
||||
public VisualScript Script { get; }
|
||||
public INode Node { get; }
|
||||
|
||||
private bool _isSelected;
|
||||
public bool IsSelected
|
||||
{
|
||||
get => _isSelected;
|
||||
private set => SetProperty(ref _isSelected, value);
|
||||
}
|
||||
|
||||
private ObservableCollection<VisualScriptPin> _inputPins = new();
|
||||
public ObservableCollection<VisualScriptPin> InputPins
|
||||
{
|
||||
get => _inputPins;
|
||||
private set => SetProperty(ref _inputPins, value);
|
||||
}
|
||||
|
||||
private ObservableCollection<VisualScriptPin> _outputPins = new();
|
||||
public ObservableCollection<VisualScriptPin> OutputPins
|
||||
{
|
||||
get => _outputPins;
|
||||
private set => SetProperty(ref _outputPins, value);
|
||||
}
|
||||
|
||||
private ObservableCollection<VisualScriptPinCollection> _inputPinCollections = new();
|
||||
public ObservableCollection<VisualScriptPinCollection> InputPinCollections
|
||||
{
|
||||
get => _inputPinCollections;
|
||||
private set => SetProperty(ref _inputPinCollections, value);
|
||||
}
|
||||
|
||||
private ObservableCollection<VisualScriptPinCollection> _outputPinCollections = new();
|
||||
public ObservableCollection<VisualScriptPinCollection> OutputPinCollections
|
||||
{
|
||||
get => _outputPinCollections;
|
||||
private set => SetProperty(ref _outputPinCollections, value);
|
||||
}
|
||||
|
||||
public double X
|
||||
{
|
||||
get => Node.X + Script.LocationOffset;
|
||||
set
|
||||
{
|
||||
Node.X = value - Script.LocationOffset;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public double Y
|
||||
{
|
||||
get => Node.Y + Script.LocationOffset;
|
||||
set
|
||||
{
|
||||
Node.Y = value - Script.LocationOffset;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Commands
|
||||
|
||||
private ActionCommand _removeCommand;
|
||||
public ActionCommand RemoveCommand => _removeCommand ??= new ActionCommand(Remove, RemoveCanExecute);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler<VisualScriptNodeIsSelectedChangedEventArgs> IsSelectedChanged;
|
||||
public event EventHandler DragStarting;
|
||||
public event EventHandler DragEnding;
|
||||
public event EventHandler<VisualScriptNodeDragMovingEventArgs> DragMoving;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public VisualScriptNode(VisualScript script, INode node)
|
||||
{
|
||||
this.Script = script;
|
||||
this.Node = node;
|
||||
|
||||
PropertyChangedEventManager.AddHandler(Node, OnNodePropertyChanged, nameof(Node.Pins));
|
||||
PropertyChangedEventManager.AddHandler(Node, OnNodePropertyChanged, nameof(Node.PinCollections));
|
||||
PropertyChangedEventManager.AddHandler(Node, OnNodePropertyChanged, nameof(Node.X));
|
||||
PropertyChangedEventManager.AddHandler(Node, OnNodePropertyChanged, nameof(Node.Y));
|
||||
|
||||
ValidatePins();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
private void OnNodePropertyChanged(object sender, PropertyChangedEventArgs args)
|
||||
{
|
||||
if (string.Equals(args.PropertyName, nameof(Node.Pins), StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(args.PropertyName, nameof(Node.PinCollections), StringComparison.OrdinalIgnoreCase))
|
||||
ValidatePins();
|
||||
|
||||
else if (string.Equals(args.PropertyName, nameof(Node.X), StringComparison.OrdinalIgnoreCase))
|
||||
OnPropertyChanged(nameof(X));
|
||||
|
||||
else if (string.Equals(args.PropertyName, nameof(Node.Y), StringComparison.OrdinalIgnoreCase))
|
||||
OnPropertyChanged(nameof(Y));
|
||||
}
|
||||
|
||||
private void ValidatePins()
|
||||
{
|
||||
if (Node == null)
|
||||
{
|
||||
InputPins.Clear();
|
||||
OutputPins.Clear();
|
||||
InputPinCollections.Clear();
|
||||
OutputPinCollections.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
#region Remove Excessive
|
||||
|
||||
HashSet<IPin> pins = new(Node.Pins);
|
||||
HashSet<IPinCollection> pinCollections = new(Node.PinCollections);
|
||||
|
||||
void ValidatePinList(ObservableCollection<VisualScriptPin> list)
|
||||
{
|
||||
List<VisualScriptPin> pinsToRemove = new();
|
||||
foreach (VisualScriptPin pin in list)
|
||||
if ((pin.Pin == null) || !pins.Contains(pin.Pin))
|
||||
pinsToRemove.Add(pin);
|
||||
foreach (VisualScriptPin pin in pinsToRemove)
|
||||
{
|
||||
pin.DisconnectAll();
|
||||
list.Remove(pin);
|
||||
}
|
||||
}
|
||||
|
||||
void ValidatePinCollectionList(ObservableCollection<VisualScriptPinCollection> list)
|
||||
{
|
||||
List<VisualScriptPinCollection> pinCollectionsToRemove = new();
|
||||
foreach (VisualScriptPinCollection pinCollection in list)
|
||||
if ((pinCollection.PinCollection == null) || !pinCollections.Contains(pinCollection.PinCollection))
|
||||
pinCollectionsToRemove.Add(pinCollection);
|
||||
foreach (VisualScriptPinCollection pinCollection in pinCollectionsToRemove)
|
||||
{
|
||||
pinCollection.RemoveAll();
|
||||
list.Remove(pinCollection);
|
||||
}
|
||||
}
|
||||
|
||||
ValidatePinList(InputPins);
|
||||
ValidatePinList(OutputPins);
|
||||
ValidatePinCollectionList(InputPinCollections);
|
||||
ValidatePinCollectionList(OutputPinCollections);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Add Missing
|
||||
|
||||
HashSet<IPin> existingPins = new(InputPins.Concat(OutputPins).Select(x => x.Pin));
|
||||
HashSet<IPinCollection> existingPinCollections = new(InputPinCollections.Concat(OutputPinCollections).Select(x => x.PinCollection));
|
||||
|
||||
foreach (IPin pin in Node.Pins)
|
||||
{
|
||||
if (pin.Direction == PinDirection.Input)
|
||||
{
|
||||
if (!existingPins.Contains(pin))
|
||||
InputPins.Add(new VisualScriptPin(this, pin));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!existingPins.Contains(pin))
|
||||
OutputPins.Add(new VisualScriptPin(this, pin));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (IPinCollection pinCollection in Node.PinCollections)
|
||||
{
|
||||
if (pinCollection.Direction == PinDirection.Input)
|
||||
{
|
||||
if (!existingPinCollections.Contains(pinCollection))
|
||||
InputPinCollections.Add(new VisualScriptPinCollection(this, pinCollection));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!existingPinCollections.Contains(pinCollection))
|
||||
OutputPinCollections.Add(new VisualScriptPinCollection(this, pinCollection));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Pin Mapping
|
||||
|
||||
_pinMapping.Clear();
|
||||
|
||||
foreach (VisualScriptPin pin in InputPins)
|
||||
_pinMapping.Add(pin.Pin, pin);
|
||||
|
||||
foreach (VisualScriptPin pin in OutputPins)
|
||||
_pinMapping.Add(pin.Pin, pin);
|
||||
|
||||
foreach (VisualScriptPinCollection pinCollection in InputPinCollections)
|
||||
foreach (VisualScriptPin pin in pinCollection.Pins)
|
||||
_pinMapping.Add(pin.Pin, pin);
|
||||
|
||||
foreach (VisualScriptPinCollection pinCollection in OutputPinCollections)
|
||||
foreach (VisualScriptPin pin in pinCollection.Pins)
|
||||
_pinMapping.Add(pin.Pin, pin);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
internal VisualScriptPin GetVisualPin(IPin pin) => ((pin != null) && _pinMapping.TryGetValue(pin, out VisualScriptPin visualScriptPin)) ? visualScriptPin : null;
|
||||
|
||||
public void SnapNodeToGrid()
|
||||
{
|
||||
X -= X % Script.GridSize;
|
||||
Y -= Y % Script.GridSize;
|
||||
}
|
||||
|
||||
public void Select(bool alterSelection = false)
|
||||
{
|
||||
IsSelected = true;
|
||||
OnIsSelectedChanged(IsSelected, alterSelection);
|
||||
}
|
||||
|
||||
public void Deselect(bool alterSelection = false)
|
||||
{
|
||||
IsSelected = false;
|
||||
OnIsSelectedChanged(IsSelected, alterSelection);
|
||||
}
|
||||
|
||||
public void DragStart() => DragStarting?.Invoke(this, EventArgs.Empty);
|
||||
public void DragEnd() => DragEnding?.Invoke(this, EventArgs.Empty);
|
||||
public void DragMove(double dx, double dy) => DragMoving?.Invoke(this, new VisualScriptNodeDragMovingEventArgs(dx, dy));
|
||||
|
||||
private void OnIsSelectedChanged(bool isSelected, bool alterSelection) => IsSelectedChanged?.Invoke(this, new VisualScriptNodeIsSelectedChangedEventArgs(isSelected, alterSelection));
|
||||
|
||||
internal void OnPinConnected(PinConnectedEventArgs args) => Script.OnPinConnected(args);
|
||||
internal void OnPinDisconnected(PinDisconnectedEventArgs args) => Script.OnPinDisconnected(args);
|
||||
|
||||
internal void OnIsConnectingPinChanged(VisualScriptPin isConnectingPin) => Script.OnIsConnectingPinChanged(isConnectingPin);
|
||||
|
||||
private void DisconnectAllPins()
|
||||
{
|
||||
foreach (VisualScriptPin pin in InputPins)
|
||||
pin.DisconnectAll();
|
||||
|
||||
foreach (VisualScriptPin pin in OutputPins)
|
||||
pin.DisconnectAll();
|
||||
|
||||
foreach (VisualScriptPinCollection pinCollection in InputPinCollections)
|
||||
foreach (VisualScriptPin pin in pinCollection.Pins)
|
||||
pin.DisconnectAll();
|
||||
|
||||
foreach (VisualScriptPinCollection pinCollection in OutputPinCollections)
|
||||
foreach (VisualScriptPin pin in pinCollection.Pins)
|
||||
pin.DisconnectAll();
|
||||
}
|
||||
|
||||
private void Remove()
|
||||
{
|
||||
DisconnectAllPins();
|
||||
Script.RemoveNode(this);
|
||||
Script.OnScriptUpdated();
|
||||
}
|
||||
|
||||
private bool RemoveCanExecute() => !Node.IsExitNode && !Node.IsDefaultNode;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Events;
|
||||
using Artemis.VisualScripting.Events;
|
||||
using Artemis.VisualScripting.Internal;
|
||||
using Artemis.VisualScripting.ViewModel;
|
||||
|
||||
namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
||||
{
|
||||
public class VisualScriptPin : AbstractBindable
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const double CABLE_OFFSET = 24 * 4;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
private bool _isConnectionUpdated = false;
|
||||
private bool _disconnectingAll = false;
|
||||
|
||||
private VisualScriptPin _isConnectingPin;
|
||||
private VisualScriptCable _isConnectingCable;
|
||||
|
||||
public VisualScriptNode Node { get; }
|
||||
public IPin Pin { get; }
|
||||
|
||||
public IReadOnlyCollection<VisualScriptCable> Connections => new ReadOnlyCollection<VisualScriptCable>(InternalConnections);
|
||||
internal ObservableCollection<VisualScriptCable> InternalConnections { get; } = new();
|
||||
|
||||
private Point _absolutePosition;
|
||||
|
||||
|
||||
public Point AbsolutePosition
|
||||
{
|
||||
get => _absolutePosition;
|
||||
internal set
|
||||
{
|
||||
if (SetProperty(ref _absolutePosition, value))
|
||||
OnPropertyChanged(nameof(AbsoluteCableTargetPosition));
|
||||
}
|
||||
}
|
||||
|
||||
public Point AbsoluteCableTargetPosition => Pin.Direction == PinDirection.Input ? new Point(AbsolutePosition.X - CABLE_OFFSET, AbsolutePosition.Y) : new Point(AbsolutePosition.X + CABLE_OFFSET, AbsolutePosition.Y);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public VisualScriptPin(VisualScriptNode node, IPin pin)
|
||||
{
|
||||
this.Node = node;
|
||||
this.Pin = pin;
|
||||
|
||||
PinConnectedEventManager.AddHandler(pin, PinConnectionChanged);
|
||||
PinDisconnectedEventManager.AddHandler(pin, PinConnectionChanged);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
private void PinConnectionChanged(object sender, SingleValueEventArgs<IPin> pin)
|
||||
{
|
||||
if (_isConnectionUpdated) return;
|
||||
|
||||
Node?.Script?.RequestCableRecreation();
|
||||
}
|
||||
|
||||
public void SetConnecting(bool isConnecting)
|
||||
{
|
||||
if (isConnecting)
|
||||
{
|
||||
if (_isConnectingCable != null)
|
||||
SetConnecting(false);
|
||||
|
||||
_isConnectingPin = new VisualScriptPin(null, new IsConnectingPin(Pin.Direction == PinDirection.Input ? PinDirection.Output : PinDirection.Input, Pin.Type)) { AbsolutePosition = AbsolutePosition };
|
||||
_isConnectingCable = new VisualScriptCable(this, _isConnectingPin);
|
||||
Node.OnIsConnectingPinChanged(_isConnectingPin);
|
||||
}
|
||||
else
|
||||
{
|
||||
_isConnectingCable.Disconnect();
|
||||
_isConnectingCable = null;
|
||||
_isConnectingPin = null;
|
||||
Node.OnIsConnectingPinChanged(_isConnectingPin);
|
||||
}
|
||||
}
|
||||
|
||||
internal void ConnectTo(VisualScriptCable cable)
|
||||
{
|
||||
if (InternalConnections.Contains(cable)) return;
|
||||
|
||||
_isConnectionUpdated = true;
|
||||
|
||||
if (Pin.Direction == PinDirection.Input)
|
||||
{
|
||||
List<VisualScriptCable> cables = InternalConnections.ToList();
|
||||
foreach (VisualScriptCable c in cables)
|
||||
c.Disconnect();
|
||||
}
|
||||
|
||||
InternalConnections.Add(cable);
|
||||
Pin.ConnectTo(cable.GetConnectedPin(Pin));
|
||||
|
||||
Node?.OnPinConnected(new PinConnectedEventArgs(this, cable));
|
||||
|
||||
if (_isConnectingPin == null)
|
||||
Node?.Script.OnScriptUpdated();
|
||||
|
||||
_isConnectionUpdated = false;
|
||||
}
|
||||
|
||||
public void DisconnectAll()
|
||||
{
|
||||
_isConnectionUpdated = true;
|
||||
_disconnectingAll = true;
|
||||
|
||||
List<VisualScriptCable> cables = InternalConnections.ToList();
|
||||
foreach (VisualScriptCable cable in cables)
|
||||
cable.Disconnect();
|
||||
|
||||
_disconnectingAll = false;
|
||||
_isConnectionUpdated = false;
|
||||
}
|
||||
|
||||
internal void Disconnect(VisualScriptCable cable)
|
||||
{
|
||||
_isConnectionUpdated = true;
|
||||
|
||||
InternalConnections.Remove(cable);
|
||||
Pin.DisconnectFrom(cable.GetConnectedPin(Pin));
|
||||
|
||||
Node?.OnPinDisconnected(new PinDisconnectedEventArgs(this, cable));
|
||||
|
||||
if (!_disconnectingAll && _isConnectingPin == null)
|
||||
Node?.Script.OnScriptUpdated();
|
||||
|
||||
_isConnectionUpdated = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Events;
|
||||
using Artemis.VisualScripting.Events;
|
||||
using Artemis.VisualScripting.ViewModel;
|
||||
|
||||
namespace Artemis.VisualScripting.Editor.Controls.Wrapper
|
||||
{
|
||||
public class VisualScriptPinCollection : AbstractBindable
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public VisualScriptNode Node { get; }
|
||||
public IPinCollection PinCollection { get; }
|
||||
|
||||
private readonly Dictionary<IPin, VisualScriptPin> _pinMapping = new();
|
||||
public ObservableCollection<VisualScriptPin> Pins { get; } = new();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Commands
|
||||
|
||||
private ActionCommand _addPinCommand;
|
||||
public ActionCommand AddPinCommand => _addPinCommand ??= new ActionCommand(AddPin);
|
||||
|
||||
private ActionCommand<VisualScriptPin> _removePinCommand;
|
||||
public ActionCommand<VisualScriptPin> RemovePinCommand => _removePinCommand ??= new ActionCommand<VisualScriptPin>(RemovePin);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public VisualScriptPinCollection(VisualScriptNode node, IPinCollection pinCollection)
|
||||
{
|
||||
this.Node = node;
|
||||
this.PinCollection = pinCollection;
|
||||
|
||||
PinAddedEventManager.AddHandler(pinCollection, OnPinCollectionPinAdded);
|
||||
PinRemovedEventManager.AddHandler(pinCollection, OnPinCollectionPinRemoved);
|
||||
|
||||
foreach (IPin pin in PinCollection)
|
||||
{
|
||||
VisualScriptPin visualScriptPin = new(node, pin);
|
||||
_pinMapping.Add(pin, visualScriptPin);
|
||||
Pins.Add(visualScriptPin);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
private void OnPinCollectionPinRemoved(object sender, SingleValueEventArgs<IPin> args)
|
||||
{
|
||||
if (!_pinMapping.TryGetValue(args.Value, out VisualScriptPin visualScriptPin)) return;
|
||||
|
||||
visualScriptPin.DisconnectAll();
|
||||
Pins.Remove(visualScriptPin);
|
||||
Node.Script.OnScriptUpdated();
|
||||
}
|
||||
|
||||
private void OnPinCollectionPinAdded(object sender, SingleValueEventArgs<IPin> args)
|
||||
{
|
||||
if (_pinMapping.ContainsKey(args.Value)) return;
|
||||
|
||||
VisualScriptPin visualScriptPin = new(Node, args.Value);
|
||||
_pinMapping.Add(args.Value, visualScriptPin);
|
||||
Pins.Add(visualScriptPin);
|
||||
Node.Script.OnScriptUpdated();
|
||||
}
|
||||
|
||||
public void AddPin() => PinCollection.Add(PinCollection.CreatePin());
|
||||
|
||||
public void RemovePin(VisualScriptPin pin) => PinCollection.Remove(pin.Pin);
|
||||
|
||||
public void RemoveAll()
|
||||
{
|
||||
List<VisualScriptPin> pins = new(Pins);
|
||||
foreach (VisualScriptPin pin in pins)
|
||||
RemovePin(pin);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Styles/VisualScriptCablePresenter.xaml" />
|
||||
<ResourceDictionary Source="Styles/VisualScriptEditor.xaml" />
|
||||
<ResourceDictionary Source="Styles/VisualScriptNodeCreationBox.xaml" />
|
||||
<ResourceDictionary Source="Styles/VisualScriptNodePresenter.xaml" />
|
||||
<ResourceDictionary Source="Styles/VisualScriptPinPresenter.xaml" />
|
||||
<ResourceDictionary Source="Styles/VisualScriptPresenter.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
@@ -1,110 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=System.Runtime"
|
||||
xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls"
|
||||
xmlns:converters="clr-namespace:Artemis.VisualScripting.Converters"
|
||||
xmlns:collections="clr-namespace:System.Collections;assembly=System.Runtime"
|
||||
xmlns:skiaSharp="clr-namespace:SkiaSharp;assembly=SkiaSharp"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared">
|
||||
<converters:CenterTranslateConverter x:Key="CenterTranslateConverter" />
|
||||
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
|
||||
<ControlTemplate x:Key="TemplateVisualScriptCablePresenter"
|
||||
TargetType="{x:Type controls:VisualScriptCablePresenter}">
|
||||
<Canvas>
|
||||
<Path x:Name="PART_Path"
|
||||
Stroke="{TemplateBinding BorderBrush}"
|
||||
StrokeThickness="{TemplateBinding Thickness}"
|
||||
StrokeStartLineCap="Round"
|
||||
StrokeEndLineCap="Round">
|
||||
<Path.Data>
|
||||
<PathGeometry>
|
||||
<PathGeometry.Figures>
|
||||
<PathFigureCollection>
|
||||
<PathFigure StartPoint="{Binding Cable.From.AbsolutePosition, RelativeSource={RelativeSource TemplatedParent}}">
|
||||
<PathFigure.Segments>
|
||||
<PathSegmentCollection>
|
||||
<BezierSegment Point1="{Binding Cable.From.AbsoluteCableTargetPosition, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Point2="{Binding Cable.To.AbsoluteCableTargetPosition, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Point3="{Binding Cable.To.AbsolutePosition, RelativeSource={RelativeSource TemplatedParent}}" />
|
||||
</PathSegmentCollection>
|
||||
</PathFigure.Segments>
|
||||
</PathFigure>
|
||||
</PathFigureCollection>
|
||||
</PathGeometry.Figures>
|
||||
</PathGeometry>
|
||||
</Path.Data>
|
||||
</Path>
|
||||
|
||||
<Border Canvas.Left="{Binding ValuePosition.X, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Canvas.Top="{Binding ValuePosition.Y, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Background="#2A2A2A"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="2"
|
||||
Padding="6"
|
||||
CornerRadius="2"
|
||||
x:Name="PART_ValueDisplay">
|
||||
<Border.RenderTransform>
|
||||
<TranslateTransform X="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=Border}, Converter={StaticResource CenterTranslateConverter}}"
|
||||
Y="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=Border}, Converter={StaticResource CenterTranslateConverter}}" />
|
||||
</Border.RenderTransform>
|
||||
|
||||
<Border.Resources>
|
||||
<DataTemplate DataType="{x:Type skiaSharp:SKColor}">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<StackPanel.Resources>
|
||||
<shared:SKColorToStringConverter x:Key="SKColorToStringConverter" />
|
||||
<shared:SKColorToColorConverter x:Key="SKColorToColorConverter" />
|
||||
</StackPanel.Resources>
|
||||
<TextBlock x:Name="HexDisplay"
|
||||
Text="{Binding Converter={StaticResource SKColorToStringConverter}}"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Stretch" />
|
||||
<Border Width="{Binding ActualHeight, ElementName=HexDisplay}"
|
||||
Height="{Binding ActualHeight, ElementName=HexDisplay}"
|
||||
CornerRadius="{Binding ActualHeight, ElementName=HexDisplay}"
|
||||
Margin="5 0 0 0"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Right"
|
||||
Background="{StaticResource Checkerboard}">
|
||||
<Ellipse Stroke="{DynamicResource NormalBorderBrush}">
|
||||
<Ellipse.Fill>
|
||||
<SolidColorBrush Color="{Binding Converter={StaticResource SKColorToColorConverter}}" />
|
||||
</Ellipse.Fill>
|
||||
</Ellipse>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</Border.Resources>
|
||||
|
||||
<Grid>
|
||||
<ContentControl Content="{Binding Cable.From.Pin.PinValue, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Visibility="{Binding Cable.From.Pin.PinValue, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource NullToVisibilityConverter}}" />
|
||||
<TextBlock Text="null"
|
||||
FontStyle="Italic"
|
||||
Visibility="{Binding Cable.From.Pin.PinValue, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}" />
|
||||
</Grid>
|
||||
|
||||
</Border>
|
||||
</Canvas>
|
||||
|
||||
</ControlTemplate>
|
||||
|
||||
<Style x:Key="StyleVisualScriptCablePresenter"
|
||||
TargetType="{x:Type controls:VisualScriptCablePresenter}">
|
||||
|
||||
<Setter Property="BorderBrush" Value="#FFFFFFFF" />
|
||||
<Setter Property="Thickness" Value="4" />
|
||||
<Setter Property="Template" Value="{StaticResource TemplateVisualScriptCablePresenter}" />
|
||||
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Thickness" Value="6" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style BasedOn="{StaticResource StyleVisualScriptCablePresenter}"
|
||||
TargetType="{x:Type controls:VisualScriptCablePresenter}" />
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -1,29 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls">
|
||||
|
||||
<ControlTemplate x:Key="TemplateVisualScriptEditor"
|
||||
TargetType="{x:Type controls:VisualScriptEditor}">
|
||||
<Border BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Background="{TemplateBinding Background}">
|
||||
<controls:VisualScriptPresenter Script="{TemplateBinding Script}"
|
||||
AvailableNodes="{TemplateBinding AvailableNodes}"
|
||||
AlwaysShowValues="{TemplateBinding AlwaysShowValues}"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
|
||||
<Style x:Key="StyleVisualScriptEditor"
|
||||
TargetType="{x:Type controls:VisualScriptEditor}">
|
||||
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="BorderBrush" Value="{x:Null}"/>
|
||||
|
||||
<Setter Property="Template" Value="{StaticResource TemplateVisualScriptEditor}" />
|
||||
</Style>
|
||||
|
||||
<Style BasedOn="{StaticResource StyleVisualScriptEditor}"
|
||||
TargetType="{x:Type controls:VisualScriptEditor}" />
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -1,92 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls"
|
||||
xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core"
|
||||
xmlns:behaviors="clr-namespace:Artemis.VisualScripting.Behaviors"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes">
|
||||
|
||||
<DataTemplate x:Key="TemplateNodeItem" DataType="{x:Type core:NodeData}">
|
||||
<StackPanel>
|
||||
<TextBlock behaviors:HighlightTermBehavior.TermToBeHighlighted="{Binding SearchInput, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=controls:VisualScriptNodeCreationBox}}"
|
||||
behaviors:HighlightTermBehavior.Text="{Binding Name}"
|
||||
behaviors:HighlightTermBehavior.HighlightForeground="{StaticResource Primary600Foreground}"
|
||||
behaviors:HighlightTermBehavior.HighlightBackground="{StaticResource Primary600}" />
|
||||
<TextBlock Foreground="{DynamicResource MaterialDesignBodyLight}"
|
||||
behaviors:HighlightTermBehavior.TermToBeHighlighted="{Binding SearchInput, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=controls:VisualScriptNodeCreationBox}}"
|
||||
behaviors:HighlightTermBehavior.Text="{Binding Description}"
|
||||
behaviors:HighlightTermBehavior.HighlightForeground="{StaticResource Primary600Foreground}"
|
||||
behaviors:HighlightTermBehavior.HighlightBackground="{StaticResource Primary600}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<ControlTemplate x:Key="TemplateVisualScriptNodeCreationBox" TargetType="{x:Type controls:VisualScriptNodeCreationBox}">
|
||||
<materialDesign:Card Margin="5" Opacity="0.9">
|
||||
<Grid Margin="8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="25" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<materialDesign:PackIcon Grid.Column="0" Kind="Search" Width="20" Height="20" VerticalAlignment="Center" Foreground="{Binding ElementName=PART_SearchBox, Path=BorderBrush}" />
|
||||
<TextBox Grid.Column="1" x:Name="PART_SearchBox"
|
||||
Text="{Binding SearchInput, UpdateSourceTrigger=PropertyChanged, Delay=300, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
materialDesign:HintAssist.Hint="Type to search..."
|
||||
materialDesign:TextFieldAssist.HasClearButton="True"/>
|
||||
</Grid>
|
||||
|
||||
<Separator Grid.Row="1" Style="{StaticResource MaterialDesignLightSeparator}" />
|
||||
|
||||
<ListBox x:Name="PART_Content" Grid.Row="2" BorderThickness="0" ItemTemplate="{StaticResource TemplateNodeItem}"
|
||||
VirtualizingPanel.IsVirtualizingWhenGrouping="True"
|
||||
VirtualizingPanel.IsContainerVirtualizable="True"
|
||||
VirtualizingPanel.ScrollUnit="Pixel">
|
||||
<ListBox.GroupStyle>
|
||||
<GroupStyle>
|
||||
<GroupStyle.ContainerStyle>
|
||||
<Style TargetType="{x:Type GroupItem}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Expander Header="{Binding Name}" IsExpanded="True">
|
||||
<Expander.HeaderTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding}" FontWeight="Bold" FontSize="16" Margin="0 8 8 8" />
|
||||
</DataTemplate>
|
||||
</Expander.HeaderTemplate>
|
||||
<Expander.Style>
|
||||
<Style TargetType="Expander">
|
||||
<Setter Property="Foreground" Value="AliceBlue" />
|
||||
</Style>
|
||||
</Expander.Style>
|
||||
<ItemsPresenter />
|
||||
</Expander>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</GroupStyle.ContainerStyle>
|
||||
</GroupStyle>
|
||||
</ListBox.GroupStyle>
|
||||
</ListBox>
|
||||
</Grid>
|
||||
</materialDesign:Card>
|
||||
</ControlTemplate>
|
||||
|
||||
<Style x:Key="StyleVisualScriptNodeCreationBox" TargetType="{x:Type controls:VisualScriptNodeCreationBox}">
|
||||
<Setter Property="Background" Value="#DD333333" />
|
||||
<Setter Property="BorderBrush" Value="#FF222222" />
|
||||
<Setter Property="BorderThickness" Value="2" />
|
||||
|
||||
<Setter Property="Template" Value="{StaticResource TemplateVisualScriptNodeCreationBox}" />
|
||||
</Style>
|
||||
|
||||
<Style BasedOn="{StaticResource StyleVisualScriptNodeCreationBox}"
|
||||
TargetType="{x:Type controls:VisualScriptNodeCreationBox}" />
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -1,261 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls"
|
||||
xmlns:wrapper="clr-namespace:Artemis.VisualScripting.Editor.Controls.Wrapper"
|
||||
xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core"
|
||||
xmlns:s="https://github.com/canton7/Stylet">
|
||||
|
||||
<Style x:Key="StyleButtonPinsModify"
|
||||
TargetType="Button">
|
||||
<Setter Property="OverridesDefaultStyle" Value="True" />
|
||||
<Setter Property="Width" Value="16" />
|
||||
<Setter Property="Height" Value="16" />
|
||||
<Setter Property="Margin" Value="0" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="HorizontalAlignment" Value="Center" />
|
||||
<Setter Property="Padding" Value="2" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="Foreground" Value="#FFA0A0A0" />
|
||||
<Setter Property="FontFamily" Value="Webdings" />
|
||||
<Setter Property="Content" Value="r" />
|
||||
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border Padding="{TemplateBinding Padding}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}">
|
||||
<TextBlock Text="{TemplateBinding Content}" />
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
||||
<Style.Triggers>
|
||||
<Trigger Property="HorizontalAlignment" Value="Left">
|
||||
<Setter Property="RenderTransformOrigin" Value="0.5,0.5" />
|
||||
<Setter Property="RenderTransform">
|
||||
<Setter.Value>
|
||||
<RotateTransform Angle="45" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
|
||||
<Trigger Property="HorizontalAlignment" Value="Right">
|
||||
<Setter Property="RenderTransformOrigin" Value="0.5,0.5" />
|
||||
<Setter Property="RenderTransform">
|
||||
<Setter.Value>
|
||||
<RotateTransform Angle="45" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Foreground" Value="#FFFFFFFF" />
|
||||
</Trigger>
|
||||
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Foreground" Value="#FFFFA0A0" />
|
||||
</Trigger>
|
||||
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="StylePinListInput"
|
||||
TargetType="ItemsControl">
|
||||
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
|
||||
<Setter Property="ItemTemplate">
|
||||
<Setter.Value>
|
||||
<DataTemplate DataType="{x:Type core:Pin}">
|
||||
<controls:VisualScriptPinPresenter Margin="0,5,0,3"
|
||||
Pin="{Binding .}" />
|
||||
</DataTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="StylePinListOutput"
|
||||
TargetType="ItemsControl">
|
||||
|
||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||
|
||||
<Setter Property="ItemTemplate">
|
||||
<Setter.Value>
|
||||
<DataTemplate DataType="{x:Type core:Pin}">
|
||||
<controls:VisualScriptPinPresenter Margin="0,5,0,3"
|
||||
Pin="{Binding .}" />
|
||||
</DataTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="StylePinCollectionListInput"
|
||||
TargetType="ItemsControl">
|
||||
|
||||
<Setter Property="ItemTemplate">
|
||||
<Setter.Value>
|
||||
<DataTemplate DataType="{x:Type wrapper:VisualScriptPinCollection}">
|
||||
<StackPanel Margin="0,2" Orientation="Vertical">
|
||||
<TextBlock Text="{Binding PinCollection.Name}" Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type controls:VisualScriptNodePresenter}}}" />
|
||||
<ItemsControl Margin="0,5"
|
||||
Style="{StaticResource StylePinListInput}"
|
||||
ItemsSource="{Binding Pins}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type core:Pin}">
|
||||
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Margin="0 8 0 0">
|
||||
<controls:VisualScriptPinPresenter Pin="{Binding .}" Margin="0 0 2 0" />
|
||||
<Button Style="{StaticResource StyleButtonPinsModify}"
|
||||
Command="{Binding DataContext.RemovePinCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"
|
||||
CommandParameter="{Binding .}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<Button HorizontalAlignment="Left"
|
||||
Margin="0,0,0,0"
|
||||
Style="{StaticResource StyleButtonPinsModify}"
|
||||
Command="{Binding AddPinCommand}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="StylePinCollectionListOutput"
|
||||
TargetType="ItemsControl">
|
||||
|
||||
<Setter Property="ItemTemplate">
|
||||
<Setter.Value>
|
||||
<DataTemplate DataType="{x:Type wrapper:VisualScriptPinCollection}">
|
||||
<StackPanel Margin="0,4" Orientation="Vertical">
|
||||
<TextBlock Text="{Binding PinCollection.Name}" Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type controls:VisualScriptNodePresenter}}}" />
|
||||
<ItemsControl Margin="0,4"
|
||||
Style="{StaticResource StylePinListOutput}"
|
||||
ItemsSource="{Binding Pins}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type core:Pin}">
|
||||
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
||||
<Button Style="{StaticResource StyleButtonPinsModify}"
|
||||
Command="{Binding DataContext.RemovePinCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"
|
||||
CommandParameter="{Binding .}" />
|
||||
<controls:VisualScriptPinPresenter Margin="-3,5,0,3"
|
||||
Pin="{Binding .}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<Button HorizontalAlignment="Right"
|
||||
Margin="0,0,0,0"
|
||||
Style="{StaticResource StyleButtonPinsModify}"
|
||||
Command="{Binding AddPinCommand}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<ControlTemplate x:Key="TemplateVisualScriptNodePresenter"
|
||||
TargetType="{x:Type controls:VisualScriptNodePresenter}">
|
||||
<Border BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Background="{TemplateBinding Background}">
|
||||
<StackPanel>
|
||||
<Border x:Name="BrdHeader"
|
||||
VerticalAlignment="Stretch"
|
||||
Height="24"
|
||||
Background="{TemplateBinding TitleBrush}">
|
||||
<DockPanel>
|
||||
<Border DockPanel.Dock="Right" Width="24">
|
||||
<Button Style="{StaticResource StyleButtonPinsModify}"
|
||||
Command="{Binding Node.RemoveCommand, RelativeSource={RelativeSource TemplatedParent}}" />
|
||||
</Border>
|
||||
<Border DockPanel.Dock="Left" Width="24">
|
||||
<!-- Placeholder -->
|
||||
</Border>
|
||||
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center"
|
||||
FontFamily="{TemplateBinding FontFamily}"
|
||||
FontSize="14" FontWeight="Bold"
|
||||
Text="{Binding Node.Node.Name, RelativeSource={RelativeSource TemplatedParent}}" />
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
<Border x:Name="BrdContent"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" MinWidth="8" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Border x:Name="BrdInputPins" Grid.Column="0">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<ItemsControl Style="{StaticResource StylePinListInput}"
|
||||
ItemsSource="{Binding Node.InputPins, RelativeSource={RelativeSource TemplatedParent}}" />
|
||||
|
||||
<ItemsControl Style="{StaticResource StylePinCollectionListInput}"
|
||||
ItemsSource="{Binding Node.InputPinCollections, RelativeSource={RelativeSource TemplatedParent}}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border x:Name="BrdCustomView" Grid.Column="1">
|
||||
<ContentControl s:View.Model="{TemplateBinding CustomViewModel}" />
|
||||
</Border>
|
||||
|
||||
<Border x:Name="BrdOutputPins" Grid.Column="2">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<ItemsControl Style="{StaticResource StylePinListOutput}"
|
||||
ItemsSource="{Binding Node.OutputPins, RelativeSource={RelativeSource TemplatedParent}}" />
|
||||
|
||||
<ItemsControl Style="{StaticResource StylePinCollectionListOutput}"
|
||||
ItemsSource="{Binding Node.OutputPinCollections, RelativeSource={RelativeSource TemplatedParent}}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
|
||||
<Style x:Key="StyleVisualScriptNodePresenter"
|
||||
TargetType="{x:Type controls:VisualScriptNodePresenter}">
|
||||
|
||||
<Setter Property="Padding" Value="8,10" />
|
||||
|
||||
<Setter Property="Foreground" Value="#FFFFFFFF" />
|
||||
|
||||
<Setter Property="Background" Value="#80101010" />
|
||||
<Setter Property="TitleBrush" Value="#FF444444" />
|
||||
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="BorderBrush" Value="#FF000000" />
|
||||
|
||||
<Setter Property="Template" Value="{StaticResource TemplateVisualScriptNodePresenter}" />
|
||||
|
||||
<Setter Property="RenderTransform">
|
||||
<Setter.Value>
|
||||
<TranslateTransform X="{Binding Node.X, RelativeSource={RelativeSource AncestorType={x:Type controls:VisualScriptNodePresenter}}}"
|
||||
Y="{Binding Node.Y, RelativeSource={RelativeSource AncestorType={x:Type controls:VisualScriptNodePresenter}}}" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Node.IsSelected, RelativeSource={RelativeSource Self}}" Value="True">
|
||||
<Setter Property="BorderBrush" Value="#FFFFFFFF" />
|
||||
<Setter Property="Background" Value="#A0101010" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style BasedOn="{StaticResource StyleVisualScriptNodePresenter}"
|
||||
TargetType="{x:Type controls:VisualScriptNodePresenter}" />
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -1,87 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls"
|
||||
xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core">
|
||||
|
||||
<ControlTemplate x:Key="TemplateVisualScriptPinPresenterInput"
|
||||
TargetType="{x:Type controls:VisualScriptPinPresenter}">
|
||||
<StackPanel VerticalAlignment="Center" Orientation="Horizontal"
|
||||
Background="Transparent">
|
||||
<Border x:Name="PART_Dot"
|
||||
VerticalAlignment="Stretch"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
Width="{Binding ActualHeight, ElementName=PART_Dot}"
|
||||
CornerRadius="{Binding ActualHeight, ElementName=PART_Dot}"
|
||||
Background="Transparent">
|
||||
<Border x:Name="VisualDot" VerticalAlignment="Stretch"
|
||||
Margin="2"
|
||||
Width="{Binding ActualHeight, ElementName=VisualDot}"
|
||||
CornerRadius="{Binding ActualHeight, ElementName=VisualDot}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Background="{TemplateBinding Background}"/>
|
||||
</Border>
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
FontFamily="{TemplateBinding FontFamily}"
|
||||
FontSize="{TemplateBinding FontSize}"
|
||||
FontStretch="{TemplateBinding FontSize}"
|
||||
FontStyle="{TemplateBinding FontStyle}"
|
||||
FontWeight="{TemplateBinding FontWeight}"
|
||||
Text="{Binding Pin.Pin.Name, RelativeSource={RelativeSource TemplatedParent}}" />
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
|
||||
<ControlTemplate x:Key="TemplateVisualScriptPinPresenterOutput"
|
||||
TargetType="{x:Type controls:VisualScriptPinPresenter}">
|
||||
<StackPanel VerticalAlignment="Center" Orientation="Horizontal"
|
||||
Background="Transparent">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
FontFamily="{TemplateBinding FontFamily}"
|
||||
FontSize="{TemplateBinding FontSize}"
|
||||
FontStretch="{TemplateBinding FontSize}"
|
||||
FontStyle="{TemplateBinding FontStyle}"
|
||||
FontWeight="{TemplateBinding FontWeight}"
|
||||
Text="{Binding Pin.Pin.Name, RelativeSource={RelativeSource TemplatedParent}}" />
|
||||
|
||||
<Border x:Name="PART_Dot"
|
||||
VerticalAlignment="Stretch"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
Width="{Binding ActualHeight, ElementName=PART_Dot}"
|
||||
CornerRadius="{Binding ActualHeight, ElementName=PART_Dot}"
|
||||
Background="Transparent">
|
||||
<Border x:Name="VisualDot" VerticalAlignment="Stretch"
|
||||
Margin="2"
|
||||
Width="{Binding ActualHeight, ElementName=VisualDot}"
|
||||
CornerRadius="{Binding ActualHeight, ElementName=VisualDot}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Background="{TemplateBinding Background}"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
|
||||
<Style x:Key="StyleVisualScriptPinPresenter"
|
||||
TargetType="{x:Type controls:VisualScriptPinPresenter}">
|
||||
|
||||
<Setter Property="Height" Value="16" />
|
||||
<Setter Property="BorderThickness" Value="2" />
|
||||
|
||||
<Setter Property="Foreground" Value="#FFFFFFFF" />
|
||||
<Setter Property="Background" Value="#A0000000" />
|
||||
<Setter Property="BorderBrush" Value="#FFFFFFFF" />
|
||||
|
||||
<Setter Property="Padding" Value="0,0,6,0" />
|
||||
<Setter Property="Template" Value="{StaticResource TemplateVisualScriptPinPresenterInput}" />
|
||||
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Pin.Pin.Direction, RelativeSource={RelativeSource Self}}" Value="{x:Static core:PinDirection.Output}">
|
||||
<Setter Property="Padding" Value="6,0,0,0" />
|
||||
<Setter Property="Template" Value="{StaticResource TemplateVisualScriptPinPresenterOutput}" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style BasedOn="{StaticResource StyleVisualScriptPinPresenter}"
|
||||
TargetType="{x:Type controls:VisualScriptPinPresenter}" />
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -1,119 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Artemis.VisualScripting.Editor.Controls">
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.Teal.xaml" />
|
||||
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<ControlTemplate x:Key="TemplateVisualScriptPresenter"
|
||||
TargetType="{x:Type controls:VisualScriptPresenter}">
|
||||
<Border BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}">
|
||||
<Grid x:Name="PART_CreationBoxParent"
|
||||
ClipToBounds="True"
|
||||
Tag="{Binding RelativeSource={RelativeSource TemplatedParent}}">
|
||||
<Grid.ContextMenu>
|
||||
<ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
|
||||
<ContextMenu.Template>
|
||||
<ControlTemplate>
|
||||
<Border Width="700" Height="300">
|
||||
<controls:VisualScriptNodeCreationBox AvailableNodes="{Binding AvailableNodes}"
|
||||
SourcePin="{Binding SourcePin}"
|
||||
CreateNodeCommand="{Binding CreateNodeCommand}" />
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</ContextMenu.Template>
|
||||
</ContextMenu>
|
||||
</Grid.ContextMenu>
|
||||
|
||||
<Canvas x:Name="PART_Canvas"
|
||||
Width="{Binding SurfaceSize, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Height="{Binding SurfaceSize, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Background="{TemplateBinding Background}">
|
||||
|
||||
<Border x:Name="PART_SelectionBorder"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{StaticResource PrimaryHueLightBrush}"
|
||||
CornerRadius="1"
|
||||
Visibility="Hidden">
|
||||
<Border.Background>
|
||||
<SolidColorBrush Color="{DynamicResource Primary400}" Opacity="0.25" />
|
||||
</Border.Background>
|
||||
</Border>
|
||||
|
||||
<ItemsControl x:Name="PART_NodeList"
|
||||
Panel.ZIndex="0">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<Canvas />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<controls:VisualScriptNodePresenter Node="{Binding .}" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
|
||||
<ItemsControl.ItemContainerStyle>
|
||||
<Style TargetType="ContentPresenter">
|
||||
<Setter Property="Panel.ZIndex" Value="0" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsSelected}" Value="True">
|
||||
<Setter Property="Panel.ZIndex" Value="1" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ItemsControl.ItemContainerStyle>
|
||||
</ItemsControl>
|
||||
|
||||
<ItemsControl x:Name="PART_CableList"
|
||||
Panel.ZIndex="-1">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<Canvas />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<controls:VisualScriptCablePresenter Cable="{Binding .}" AlwaysShowValues="{Binding AlwaysShowValues, RelativeSource={RelativeSource AncestorType=controls:VisualScriptPresenter}}"/>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
|
||||
<Style x:Key="StyleVisualScriptPresenter"
|
||||
TargetType="{x:Type controls:VisualScriptPresenter}">
|
||||
<Setter Property="Template" Value="{StaticResource TemplateVisualScriptPresenter}" />
|
||||
|
||||
<Setter Property="SurfaceSize" Value="16384" />
|
||||
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<VisualBrush TileMode="Tile" Stretch="Uniform" Viewport="0 0 24 24" ViewportUnits="Absolute">
|
||||
<VisualBrush.Visual>
|
||||
<Canvas>
|
||||
<Rectangle Width="12" Height="12" Canvas.Top="0" Canvas.Left="0" Fill="Black" Opacity="0.15" />
|
||||
<Rectangle Width="12" Height="12" Canvas.Top="0" Canvas.Left="12" />
|
||||
<Rectangle Width="12" Height="12" Canvas.Top="12" Canvas.Left="0" />
|
||||
<Rectangle Width="12" Height="12" Canvas.Top="12" Canvas.Left="12" Fill="Black" Opacity="0.15" />
|
||||
</Canvas>
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
</Style>
|
||||
|
||||
<Style BasedOn="{StaticResource StyleVisualScriptPresenter}"
|
||||
TargetType="{x:Type controls:VisualScriptPresenter}" />
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -1,77 +0,0 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Events;
|
||||
|
||||
namespace Artemis.VisualScripting.Events
|
||||
{
|
||||
public class NodeAddedEventManager : WeakEventManager
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private static NodeAddedEventManager CurrentManager
|
||||
{
|
||||
get
|
||||
{
|
||||
Type type = typeof(NodeAddedEventManager);
|
||||
NodeAddedEventManager changedEventManager = (NodeAddedEventManager)GetCurrentManager(type);
|
||||
if (changedEventManager == null)
|
||||
{
|
||||
changedEventManager = new NodeAddedEventManager();
|
||||
SetCurrentManager(type, changedEventManager);
|
||||
}
|
||||
return changedEventManager;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
private NodeAddedEventManager()
|
||||
{ }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public static void AddListener(INodeScript source, IWeakEventListener listener)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException(nameof(source));
|
||||
if (listener == null) throw new ArgumentNullException(nameof(listener));
|
||||
|
||||
CurrentManager.ProtectedAddListener(source, listener);
|
||||
}
|
||||
|
||||
public static void RemoveListener(INodeScript source, IWeakEventListener listener)
|
||||
{
|
||||
if (listener == null) throw new ArgumentNullException(nameof(listener));
|
||||
|
||||
CurrentManager.ProtectedRemoveListener(source, listener);
|
||||
}
|
||||
|
||||
public static void AddHandler(INodeScript source, EventHandler<SingleValueEventArgs<INode>> handler)
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
CurrentManager.ProtectedAddHandler(source, handler);
|
||||
}
|
||||
|
||||
public static void RemoveHandler(INodeScript source, EventHandler<SingleValueEventArgs<INode>> handler)
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
CurrentManager.ProtectedRemoveHandler(source, handler);
|
||||
}
|
||||
|
||||
protected override ListenerList NewListenerList() => new ListenerList<SingleValueEventArgs<INode>>();
|
||||
|
||||
protected override void StartListening(object source) => ((INodeScript)source).NodeAdded += OnNodeAdded;
|
||||
|
||||
protected override void StopListening(object source) => ((INodeScript)source).NodeAdded -= OnNodeAdded;
|
||||
|
||||
private void OnNodeAdded(object sender, SingleValueEventArgs<INode> args) => DeliverEvent(sender, args);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Events;
|
||||
|
||||
namespace Artemis.VisualScripting.Events
|
||||
{
|
||||
public class NodeRemovedEventManager : WeakEventManager
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private static NodeRemovedEventManager CurrentManager
|
||||
{
|
||||
get
|
||||
{
|
||||
Type type = typeof(NodeRemovedEventManager);
|
||||
NodeRemovedEventManager changedEventManager = (NodeRemovedEventManager)GetCurrentManager(type);
|
||||
if (changedEventManager == null)
|
||||
{
|
||||
changedEventManager = new NodeRemovedEventManager();
|
||||
SetCurrentManager(type, changedEventManager);
|
||||
}
|
||||
return changedEventManager;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
private NodeRemovedEventManager()
|
||||
{ }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public static void AddListener(INodeScript source, IWeakEventListener listener)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException(nameof(source));
|
||||
if (listener == null) throw new ArgumentNullException(nameof(listener));
|
||||
|
||||
CurrentManager.ProtectedAddListener(source, listener);
|
||||
}
|
||||
|
||||
public static void RemoveListener(INodeScript source, IWeakEventListener listener)
|
||||
{
|
||||
if (listener == null) throw new ArgumentNullException(nameof(listener));
|
||||
|
||||
CurrentManager.ProtectedRemoveListener(source, listener);
|
||||
}
|
||||
|
||||
public static void AddHandler(INodeScript source, EventHandler<SingleValueEventArgs<INode>> handler)
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
CurrentManager.ProtectedAddHandler(source, handler);
|
||||
}
|
||||
|
||||
public static void RemoveHandler(INodeScript source, EventHandler<SingleValueEventArgs<INode>> handler)
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
CurrentManager.ProtectedRemoveHandler(source, handler);
|
||||
}
|
||||
|
||||
protected override ListenerList NewListenerList() => new ListenerList<SingleValueEventArgs<INode>>();
|
||||
|
||||
protected override void StartListening(object source) => ((INodeScript)source).NodeRemoved += OnNodeRemoved;
|
||||
|
||||
protected override void StopListening(object source) => ((INodeScript)source).NodeRemoved -= OnNodeRemoved;
|
||||
|
||||
private void OnNodeRemoved(object sender, SingleValueEventArgs<INode> args) => DeliverEvent(sender, args);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Events;
|
||||
|
||||
namespace Artemis.VisualScripting.Events
|
||||
{
|
||||
public class PinAddedEventManager : WeakEventManager
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private static PinAddedEventManager CurrentManager
|
||||
{
|
||||
get
|
||||
{
|
||||
Type type = typeof(PinAddedEventManager);
|
||||
PinAddedEventManager changedEventManager = (PinAddedEventManager)GetCurrentManager(type);
|
||||
if (changedEventManager == null)
|
||||
{
|
||||
changedEventManager = new PinAddedEventManager();
|
||||
SetCurrentManager(type, changedEventManager);
|
||||
}
|
||||
return changedEventManager;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
private PinAddedEventManager()
|
||||
{ }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public static void AddListener(IPinCollection source, IWeakEventListener listener)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException(nameof(source));
|
||||
if (listener == null) throw new ArgumentNullException(nameof(listener));
|
||||
|
||||
CurrentManager.ProtectedAddListener(source, listener);
|
||||
}
|
||||
|
||||
public static void RemoveListener(IPinCollection source, IWeakEventListener listener)
|
||||
{
|
||||
if (listener == null) throw new ArgumentNullException(nameof(listener));
|
||||
|
||||
CurrentManager.ProtectedRemoveListener(source, listener);
|
||||
}
|
||||
|
||||
public static void AddHandler(IPinCollection source, EventHandler<SingleValueEventArgs<IPin>> handler)
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
CurrentManager.ProtectedAddHandler(source, handler);
|
||||
}
|
||||
|
||||
public static void RemoveHandler(IPinCollection source, EventHandler<SingleValueEventArgs<IPin>> handler)
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
CurrentManager.ProtectedRemoveHandler(source, handler);
|
||||
}
|
||||
|
||||
protected override ListenerList NewListenerList() => new ListenerList<SingleValueEventArgs<IPin>>();
|
||||
|
||||
protected override void StartListening(object source) => ((IPinCollection)source).PinAdded += OnPinAdded;
|
||||
|
||||
protected override void StopListening(object source) => ((IPinCollection)source).PinAdded -= OnPinAdded;
|
||||
|
||||
private void OnPinAdded(object sender, SingleValueEventArgs<IPin> args) => DeliverEvent(sender, args);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using System;
|
||||
using Artemis.VisualScripting.Editor.Controls.Wrapper;
|
||||
|
||||
namespace Artemis.VisualScripting.Events
|
||||
{
|
||||
public class PinConnectedEventArgs : EventArgs
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public VisualScriptPin Pin { get; }
|
||||
public VisualScriptCable Cable { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public PinConnectedEventArgs(VisualScriptPin pin, VisualScriptCable cable)
|
||||
{
|
||||
this.Pin = pin;
|
||||
this.Cable = cable;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Events;
|
||||
|
||||
namespace Artemis.VisualScripting.Events
|
||||
{
|
||||
public class PinConnectedEventManager : WeakEventManager
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private static PinConnectedEventManager CurrentManager
|
||||
{
|
||||
get
|
||||
{
|
||||
Type type = typeof(PinConnectedEventManager);
|
||||
PinConnectedEventManager changedEventManager = (PinConnectedEventManager)GetCurrentManager(type);
|
||||
if (changedEventManager == null)
|
||||
{
|
||||
changedEventManager = new PinConnectedEventManager();
|
||||
SetCurrentManager(type, changedEventManager);
|
||||
}
|
||||
return changedEventManager;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
private PinConnectedEventManager()
|
||||
{ }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public static void AddListener(IPin source, IWeakEventListener listener)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException(nameof(source));
|
||||
if (listener == null) throw new ArgumentNullException(nameof(listener));
|
||||
|
||||
CurrentManager.ProtectedAddListener(source, listener);
|
||||
}
|
||||
|
||||
public static void RemoveListener(IPin source, IWeakEventListener listener)
|
||||
{
|
||||
if (listener == null) throw new ArgumentNullException(nameof(listener));
|
||||
|
||||
CurrentManager.ProtectedRemoveListener(source, listener);
|
||||
}
|
||||
|
||||
public static void AddHandler(IPin source, EventHandler<SingleValueEventArgs<IPin>> handler)
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
CurrentManager.ProtectedAddHandler(source, handler);
|
||||
}
|
||||
|
||||
public static void RemoveHandler(IPin source, EventHandler<SingleValueEventArgs<IPin>> handler)
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
CurrentManager.ProtectedRemoveHandler(source, handler);
|
||||
}
|
||||
|
||||
protected override ListenerList NewListenerList() => new ListenerList<SingleValueEventArgs<IPin>>();
|
||||
|
||||
protected override void StartListening(object source) => ((IPin)source).PinConnected += OnPinConnected;
|
||||
|
||||
protected override void StopListening(object source) => ((IPin)source).PinConnected -= OnPinConnected;
|
||||
|
||||
private void OnPinConnected(object sender, SingleValueEventArgs<IPin> args) => DeliverEvent(sender, args);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using System;
|
||||
using Artemis.VisualScripting.Editor.Controls.Wrapper;
|
||||
|
||||
namespace Artemis.VisualScripting.Events
|
||||
{
|
||||
public class PinDisconnectedEventArgs : EventArgs
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public VisualScriptPin Pin { get; }
|
||||
public VisualScriptCable Cable { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public PinDisconnectedEventArgs(VisualScriptPin pin, VisualScriptCable cable)
|
||||
{
|
||||
this.Pin = pin;
|
||||
this.Cable = cable;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Events;
|
||||
|
||||
namespace Artemis.VisualScripting.Events
|
||||
{
|
||||
public class PinDisconnectedEventManager : WeakEventManager
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private static PinDisconnectedEventManager CurrentManager
|
||||
{
|
||||
get
|
||||
{
|
||||
Type type = typeof(PinDisconnectedEventManager);
|
||||
PinDisconnectedEventManager changedEventManager = (PinDisconnectedEventManager)GetCurrentManager(type);
|
||||
if (changedEventManager == null)
|
||||
{
|
||||
changedEventManager = new PinDisconnectedEventManager();
|
||||
SetCurrentManager(type, changedEventManager);
|
||||
}
|
||||
return changedEventManager;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
private PinDisconnectedEventManager()
|
||||
{ }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public static void AddListener(IPin source, IWeakEventListener listener)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException(nameof(source));
|
||||
if (listener == null) throw new ArgumentNullException(nameof(listener));
|
||||
|
||||
CurrentManager.ProtectedAddListener(source, listener);
|
||||
}
|
||||
|
||||
public static void RemoveListener(IPin source, IWeakEventListener listener)
|
||||
{
|
||||
if (listener == null) throw new ArgumentNullException(nameof(listener));
|
||||
|
||||
CurrentManager.ProtectedRemoveListener(source, listener);
|
||||
}
|
||||
|
||||
public static void AddHandler(IPin source, EventHandler<SingleValueEventArgs<IPin>> handler)
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
CurrentManager.ProtectedAddHandler(source, handler);
|
||||
}
|
||||
|
||||
public static void RemoveHandler(IPin source, EventHandler<SingleValueEventArgs<IPin>> handler)
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
CurrentManager.ProtectedRemoveHandler(source, handler);
|
||||
}
|
||||
|
||||
protected override ListenerList NewListenerList() => new ListenerList<SingleValueEventArgs<IPin>>();
|
||||
|
||||
protected override void StartListening(object source) => ((IPin)source).PinDisconnected += OnPinDisconnected;
|
||||
|
||||
protected override void StopListening(object source) => ((IPin)source).PinDisconnected -= OnPinDisconnected;
|
||||
|
||||
private void OnPinDisconnected(object sender, SingleValueEventArgs<IPin> args) => DeliverEvent(sender, args);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Events;
|
||||
|
||||
namespace Artemis.VisualScripting.Events
|
||||
{
|
||||
public class PinRemovedEventManager : WeakEventManager
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private static PinRemovedEventManager CurrentManager
|
||||
{
|
||||
get
|
||||
{
|
||||
Type type = typeof(PinRemovedEventManager);
|
||||
PinRemovedEventManager changedEventManager = (PinRemovedEventManager)GetCurrentManager(type);
|
||||
if (changedEventManager == null)
|
||||
{
|
||||
changedEventManager = new PinRemovedEventManager();
|
||||
SetCurrentManager(type, changedEventManager);
|
||||
}
|
||||
return changedEventManager;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
private PinRemovedEventManager()
|
||||
{ }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public static void AddListener(IPinCollection source, IWeakEventListener listener)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException(nameof(source));
|
||||
if (listener == null) throw new ArgumentNullException(nameof(listener));
|
||||
|
||||
CurrentManager.ProtectedAddListener(source, listener);
|
||||
}
|
||||
|
||||
public static void RemoveListener(IPinCollection source, IWeakEventListener listener)
|
||||
{
|
||||
if (listener == null) throw new ArgumentNullException(nameof(listener));
|
||||
|
||||
CurrentManager.ProtectedRemoveListener(source, listener);
|
||||
}
|
||||
|
||||
public static void AddHandler(IPinCollection source, EventHandler<SingleValueEventArgs<IPin>> handler)
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
CurrentManager.ProtectedAddHandler(source, handler);
|
||||
}
|
||||
|
||||
public static void RemoveHandler(IPinCollection source, EventHandler<SingleValueEventArgs<IPin>> handler)
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
CurrentManager.ProtectedRemoveHandler(source, handler);
|
||||
}
|
||||
|
||||
protected override ListenerList NewListenerList() => new ListenerList<SingleValueEventArgs<IPin>>();
|
||||
|
||||
protected override void StartListening(object source) => ((IPinCollection)source).PinRemoved += OnPinRemoved;
|
||||
|
||||
protected override void StopListening(object source) => ((IPinCollection)source).PinRemoved -= OnPinRemoved;
|
||||
|
||||
private void OnPinRemoved(object sender, SingleValueEventArgs<IPin> args) => DeliverEvent(sender, args);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Artemis.VisualScripting.Events
|
||||
{
|
||||
public class VisualScriptNodeDragMovingEventArgs : EventArgs
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public double DX { get; }
|
||||
public double DY { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public VisualScriptNodeDragMovingEventArgs(double dx, double dy)
|
||||
{
|
||||
this.DX = dx;
|
||||
this.DY = dy;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Artemis.VisualScripting.Events
|
||||
{
|
||||
public class VisualScriptNodeIsSelectedChangedEventArgs : EventArgs
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public bool IsSelected { get; }
|
||||
public bool AlterSelection { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public VisualScriptNodeIsSelectedChangedEventArgs(bool isSelected, bool alterSelection)
|
||||
{
|
||||
this.IsSelected = isSelected;
|
||||
this.AlterSelection = alterSelection;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using System;
|
||||
using Artemis.Core;
|
||||
|
||||
namespace Artemis.VisualScripting.Internal
|
||||
{
|
||||
internal class IsConnectingPin : Pin
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public override PinDirection Direction { get; }
|
||||
public override Type Type { get; }
|
||||
public override object PinValue => null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public IsConnectingPin(PinDirection direction, Type type)
|
||||
: base(null, null)
|
||||
{
|
||||
this.Direction = direction;
|
||||
this.Type = type;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,302 +1,299 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Collections;
|
||||
using Artemis.Core;
|
||||
using Artemis.VisualScripting.Nodes.CustomViewModels;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes
|
||||
namespace Artemis.VisualScripting.Nodes;
|
||||
|
||||
[Node("Greater than", "Checks if the first input is greater than the second.", "Operators", InputType = typeof(object), OutputType = typeof(bool))]
|
||||
public class GreaterThanNode : Node
|
||||
{
|
||||
[Node("Greater than", "Checks if the first input is greater than the second.", "Operators", InputType = typeof(object), OutputType = typeof(bool))]
|
||||
public class GreaterThanNode : Node
|
||||
#region Constructors
|
||||
|
||||
public GreaterThanNode()
|
||||
: base("Greater than", "Checks if the first input is greater than the second.")
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPin<object> Input1 { get; }
|
||||
public InputPin<object> Input2 { get; }
|
||||
|
||||
public OutputPin<bool> Result { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public GreaterThanNode()
|
||||
: base("Greater than", "Checks if the first input is greater than the second.")
|
||||
{
|
||||
Input1 = CreateInputPin<object>();
|
||||
Input2 = CreateInputPin<object>();
|
||||
Result = CreateOutputPin<bool>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
if (Input1.Value is Numeric numeric1 && Input2.Value is Numeric numeric2)
|
||||
{
|
||||
Result.Value = numeric1 > numeric2;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Input2.Value != null && Input1.Value != null && Input1.Value.IsNumber() && Input2.Value.IsNumber())
|
||||
{
|
||||
Result.Value = Convert.ToSingle(Input1.Value) > Convert.ToSingle(Input2.Value);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Result.Value = Comparer.DefaultInvariant.Compare(Input1.Value, Input2.Value) == 1;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Result.Value = false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
Input1 = CreateInputPin<object>();
|
||||
Input2 = CreateInputPin<object>();
|
||||
Result = CreateOutputPin<bool>();
|
||||
}
|
||||
|
||||
[Node("Less than", "Checks if the first input is less than the second.", "Operators", InputType = typeof(object), OutputType = typeof(bool))]
|
||||
public class LessThanNode : Node
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPin<object> Input1 { get; }
|
||||
public InputPin<object> Input2 { get; }
|
||||
|
||||
public OutputPin<bool> Result { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public LessThanNode()
|
||||
: base("Less than", "Checks if the first input is less than the second.")
|
||||
if (Input1.Value is Numeric numeric1 && Input2.Value is Numeric numeric2)
|
||||
{
|
||||
Input1 = CreateInputPin<object>();
|
||||
Input2 = CreateInputPin<object>();
|
||||
Result = CreateOutputPin<bool>();
|
||||
Result.Value = numeric1 > numeric2;
|
||||
return;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
if (Input2.Value != null && Input1.Value != null && Input1.Value.IsNumber() && Input2.Value.IsNumber())
|
||||
{
|
||||
if (Input1.Value is Numeric numeric1 && Input2.Value is Numeric numeric2)
|
||||
{
|
||||
Result.Value = numeric1 < numeric2;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Input2.Value != null && Input1.Value != null && Input1.Value.IsNumber() && Input2.Value.IsNumber())
|
||||
{
|
||||
Result.Value = Convert.ToSingle(Input1.Value) < Convert.ToSingle(Input2.Value);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Result.Value = Comparer.DefaultInvariant.Compare(Input1.Value, Input2.Value) == -1;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Result.Value = false;
|
||||
}
|
||||
Result.Value = Convert.ToSingle(Input1.Value) > Convert.ToSingle(Input2.Value);
|
||||
return;
|
||||
}
|
||||
|
||||
#endregion
|
||||
try
|
||||
{
|
||||
Result.Value = Comparer.DefaultInvariant.Compare(Input1.Value, Input2.Value) == 1;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Result.Value = false;
|
||||
}
|
||||
}
|
||||
|
||||
[Node("Equals", "Checks if the two inputs are equals.", "Operators", InputType = typeof(bool), OutputType = typeof(bool))]
|
||||
public class EqualsNode : Node
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPin<object> Input1 { get; }
|
||||
public InputPin<object> Input2 { get; }
|
||||
|
||||
public OutputPin<bool> Result { get; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Node("Less than", "Checks if the first input is less than the second.", "Operators", InputType = typeof(object), OutputType = typeof(bool))]
|
||||
public class LessThanNode : Node
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public LessThanNode()
|
||||
: base("Less than", "Checks if the first input is less than the second.")
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPin<object> Input1 { get; }
|
||||
public InputPin<object> Input2 { get; }
|
||||
|
||||
public OutputPin<bool> Result { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public EqualsNode()
|
||||
: base("Equals", "Checks if the two inputs are equals.")
|
||||
{
|
||||
Input1 = CreateInputPin<object>();
|
||||
Input2 = CreateInputPin<object>();
|
||||
Result = CreateOutputPin<bool>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
try
|
||||
{
|
||||
Result.Value = Equals(Input1.Value, Input2.Value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Result.Value = false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
Input1 = CreateInputPin<object>();
|
||||
Input2 = CreateInputPin<object>();
|
||||
Result = CreateOutputPin<bool>();
|
||||
}
|
||||
|
||||
[Node("Negate", "Negates the boolean.", "Operators", InputType = typeof(bool), OutputType = typeof(bool))]
|
||||
public class NegateNode : Node
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPin<bool> Input { get; }
|
||||
public OutputPin<bool> Output { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public NegateNode()
|
||||
: base("Negate", "Negates the boolean.")
|
||||
if (Input1.Value is Numeric numeric1 && Input2.Value is Numeric numeric2)
|
||||
{
|
||||
Input = CreateInputPin<bool>();
|
||||
Output = CreateOutputPin<bool>();
|
||||
Result.Value = numeric1 < numeric2;
|
||||
return;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
if (Input2.Value != null && Input1.Value != null && Input1.Value.IsNumber() && Input2.Value.IsNumber())
|
||||
{
|
||||
Output.Value = !Input.Value;
|
||||
Result.Value = Convert.ToSingle(Input1.Value) < Convert.ToSingle(Input2.Value);
|
||||
return;
|
||||
}
|
||||
|
||||
#endregion
|
||||
try
|
||||
{
|
||||
Result.Value = Comparer.DefaultInvariant.Compare(Input1.Value, Input2.Value) == -1;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Result.Value = false;
|
||||
}
|
||||
}
|
||||
|
||||
[Node("And", "Checks if all inputs are true.", "Operators", InputType = typeof(bool), OutputType = typeof(bool))]
|
||||
public class AndNode : Node
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPin<object> Input1 { get; }
|
||||
public InputPin<object> Input2 { get; }
|
||||
|
||||
public OutputPin<bool> Result { get; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Node("Equals", "Checks if the two inputs are equals.", "Operators", InputType = typeof(bool), OutputType = typeof(bool))]
|
||||
public class EqualsNode : Node
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public EqualsNode()
|
||||
: base("Equals", "Checks if the two inputs are equals.")
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPinCollection<bool> Input { get; set; }
|
||||
public OutputPin<bool> Result { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public AndNode()
|
||||
: base("And", "Checks if all inputs are true.")
|
||||
{
|
||||
Input = CreateInputPinCollection<bool>();
|
||||
Result = CreateOutputPin<bool>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Result.Value = Input.Values.All(v => v);
|
||||
}
|
||||
|
||||
#endregion
|
||||
Input1 = CreateInputPin<object>();
|
||||
Input2 = CreateInputPin<object>();
|
||||
Result = CreateOutputPin<bool>();
|
||||
}
|
||||
|
||||
[Node("Or", "Checks if any inputs are true.", "Operators", InputType = typeof(bool), OutputType = typeof(bool))]
|
||||
public class OrNode : Node
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPinCollection<bool> Input { get; set; }
|
||||
public OutputPin<bool> Result { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public OrNode()
|
||||
: base("Or", "Checks if any inputs are true.")
|
||||
try
|
||||
{
|
||||
Input = CreateInputPinCollection<bool>();
|
||||
Result = CreateOutputPin<bool>();
|
||||
Result.Value = Equals(Input1.Value, Input2.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
catch
|
||||
{
|
||||
Result.Value = Input.Values.Any(v => v);
|
||||
Result.Value = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Node("Exclusive Or", "Checks if one of the inputs is true.", "Operators", InputType = typeof(bool), OutputType = typeof(bool))]
|
||||
public class XorNode : Node
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPin<object> Input1 { get; }
|
||||
public InputPin<object> Input2 { get; }
|
||||
|
||||
public OutputPin<bool> Result { get; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Node("Negate", "Negates the boolean.", "Operators", InputType = typeof(bool), OutputType = typeof(bool))]
|
||||
public class NegateNode : Node
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public NegateNode()
|
||||
: base("Negate", "Negates the boolean.")
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPinCollection<bool> Input { get; set; }
|
||||
public OutputPin<bool> Result { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public XorNode()
|
||||
: base("Exclusive Or", "Checks if one of the inputs is true.")
|
||||
{
|
||||
Input = CreateInputPinCollection<bool>();
|
||||
Result = CreateOutputPin<bool>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Result.Value = Input.Values.Count(v => v) == 1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
Input = CreateInputPin<bool>();
|
||||
Output = CreateOutputPin<bool>();
|
||||
}
|
||||
|
||||
[Node("Enum Equals", "Determines the equality between an input and a selected enum value", "Operators", InputType = typeof(Enum), OutputType = typeof(bool))]
|
||||
public class EnumEqualsNode : Node<Enum, EnumEqualsNodeCustomViewModel>
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
public EnumEqualsNode() : base("Enum Equals", "Determines the equality between an input and a selected enum value")
|
||||
{
|
||||
InputPin = CreateInputPin<Enum>();
|
||||
OutputPin = CreateOutputPin<bool>();
|
||||
}
|
||||
|
||||
public InputPin<Enum> InputPin { get; }
|
||||
public OutputPin<bool> OutputPin { get; }
|
||||
|
||||
#region Overrides of Node
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Evaluate()
|
||||
{
|
||||
OutputPin.Value = InputPin.Value != null && InputPin.Value.Equals(Storage);
|
||||
}
|
||||
|
||||
#endregion
|
||||
Output.Value = !Input.Value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPin<bool> Input { get; }
|
||||
public OutputPin<bool> Output { get; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Node("And", "Checks if all inputs are true.", "Operators", InputType = typeof(bool), OutputType = typeof(bool))]
|
||||
public class AndNode : Node
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public AndNode()
|
||||
: base("And", "Checks if all inputs are true.")
|
||||
{
|
||||
Input = CreateInputPinCollection<bool>();
|
||||
Result = CreateOutputPin<bool>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Result.Value = Input.Values.All(v => v);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPinCollection<bool> Input { get; set; }
|
||||
public OutputPin<bool> Result { get; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Node("Or", "Checks if any inputs are true.", "Operators", InputType = typeof(bool), OutputType = typeof(bool))]
|
||||
public class OrNode : Node
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public OrNode()
|
||||
: base("Or", "Checks if any inputs are true.")
|
||||
{
|
||||
Input = CreateInputPinCollection<bool>();
|
||||
Result = CreateOutputPin<bool>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Result.Value = Input.Values.Any(v => v);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPinCollection<bool> Input { get; set; }
|
||||
public OutputPin<bool> Result { get; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Node("Exclusive Or", "Checks if one of the inputs is true.", "Operators", InputType = typeof(bool), OutputType = typeof(bool))]
|
||||
public class XorNode : Node
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public XorNode()
|
||||
: base("Exclusive Or", "Checks if one of the inputs is true.")
|
||||
{
|
||||
Input = CreateInputPinCollection<bool>();
|
||||
Result = CreateOutputPin<bool>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Result.Value = Input.Values.Count(v => v) == 1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPinCollection<bool> Input { get; set; }
|
||||
public OutputPin<bool> Result { get; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Node("Enum Equals", "Determines the equality between an input and a selected enum value", "Operators", InputType = typeof(Enum), OutputType = typeof(bool))]
|
||||
public class EnumEqualsNode : Node<Enum, EnumEqualsNodeCustomViewModel>
|
||||
{
|
||||
public EnumEqualsNode() : base("Enum Equals", "Determines the equality between an input and a selected enum value")
|
||||
{
|
||||
InputPin = CreateInputPin<Enum>();
|
||||
OutputPin = CreateOutputPin<bool>();
|
||||
}
|
||||
|
||||
public InputPin<Enum> InputPin { get; }
|
||||
public OutputPin<bool> OutputPin { get; }
|
||||
|
||||
#region Overrides of Node
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Evaluate()
|
||||
{
|
||||
OutputPin.Value = InputPin.Value != null && InputPin.Value.Equals(Storage);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,27 +1,26 @@
|
||||
using Artemis.Core;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Color
|
||||
namespace Artemis.VisualScripting.Nodes.Color;
|
||||
|
||||
[Node("Brighten Color", "Brightens a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||
public class BrightenSKColorNode : Node
|
||||
{
|
||||
[Node("Brighten Color", "Brightens a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||
public class BrightenSKColorNode : Node
|
||||
public BrightenSKColorNode() : base("Brighten Color", "Brightens a color by a specified amount in percent")
|
||||
{
|
||||
public BrightenSKColorNode() : base("Brighten Color", "Brightens a color by a specified amount in percent")
|
||||
{
|
||||
Input = CreateInputPin<SKColor>("Color");
|
||||
Percentage = CreateInputPin<Numeric>("%");
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
}
|
||||
Input = CreateInputPin<SKColor>("Color");
|
||||
Percentage = CreateInputPin<Numeric>("%");
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
}
|
||||
|
||||
public InputPin<SKColor> Input { get; }
|
||||
public InputPin<Numeric> Percentage { get; }
|
||||
public OutputPin<SKColor> Output { get; set; }
|
||||
public InputPin<SKColor> Input { get; }
|
||||
public InputPin<Numeric> Percentage { get; }
|
||||
public OutputPin<SKColor> Output { get; set; }
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Input.Value.ToHsl(out float h, out float s, out float l);
|
||||
l += l * (Percentage.Value / 100f);
|
||||
Output.Value = SKColor.FromHsl(h, s, l);
|
||||
}
|
||||
public override void Evaluate()
|
||||
{
|
||||
Input.Value.ToHsl(out float h, out float s, out float l);
|
||||
l += l * (Percentage.Value / 100f);
|
||||
Output.Value = SKColor.FromHsl(h, s, l);
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -1,11 +1,11 @@
|
||||
using Artemis.VisualScripting.Nodes.CustomViewModels;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared.VisualScripting;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Color.CustomViewModels
|
||||
namespace Artemis.VisualScripting.Nodes.Color.CustomViewModels;
|
||||
|
||||
public class StaticSKColorValueNodeCustomViewModel : CustomNodeViewModel
|
||||
{
|
||||
public class StaticSKColorValueNodeCustomViewModel : CustomNodeViewModel
|
||||
public StaticSKColorValueNodeCustomViewModel(StaticSKColorValueNode node, INodeScript script) : base(node, script)
|
||||
{
|
||||
public StaticSKColorValueNodeCustomViewModel(StaticSKColorValueNode node) : base(node)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-5
@@ -1,11 +1,10 @@
|
||||
<UserControl x:Class="Artemis.VisualScripting.Nodes.Color.CustomViews.StaticSKColorValueNodeCustomView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.VisualScripting.Nodes.Color.CustomViews"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<shared:SKColorToColorConverter x:Key="SKColorToColorConverter" />
|
||||
@@ -13,4 +12,4 @@
|
||||
<shared:ColorPicker VerticalAlignment="Center"
|
||||
HorizontalAlignment="Stretch"
|
||||
Color="{Binding Node.Storage, Converter={StaticResource SKColorToColorConverter}}" />
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
@@ -1,27 +1,26 @@
|
||||
using Artemis.Core;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Color
|
||||
namespace Artemis.VisualScripting.Nodes.Color;
|
||||
|
||||
[Node("Darken Color", "Darkens a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||
public class DarkenSKColorNode : Node
|
||||
{
|
||||
[Node("Darken Color", "Darkens a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||
public class DarkenSKColorNode : Node
|
||||
public DarkenSKColorNode() : base("Darken Color", "Darkens a color by a specified amount in percent")
|
||||
{
|
||||
public DarkenSKColorNode() : base("Darken Color", "Darkens a color by a specified amount in percent")
|
||||
{
|
||||
Input = CreateInputPin<SKColor>("Color");
|
||||
Percentage = CreateInputPin<Numeric>("%");
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
}
|
||||
Input = CreateInputPin<SKColor>("Color");
|
||||
Percentage = CreateInputPin<Numeric>("%");
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
}
|
||||
|
||||
public InputPin<SKColor> Input { get; }
|
||||
public InputPin<Numeric> Percentage { get; }
|
||||
public OutputPin<SKColor> Output { get; set; }
|
||||
public InputPin<SKColor> Input { get; }
|
||||
public InputPin<Numeric> Percentage { get; }
|
||||
public OutputPin<SKColor> Output { get; set; }
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Input.Value.ToHsl(out float h, out float s, out float l);
|
||||
l -= l * (Percentage.Value / 100f);
|
||||
Output.Value = SKColor.FromHsl(h, s, l);
|
||||
}
|
||||
public override void Evaluate()
|
||||
{
|
||||
Input.Value.ToHsl(out float h, out float s, out float l);
|
||||
l -= l * (Percentage.Value / 100f);
|
||||
Output.Value = SKColor.FromHsl(h, s, l);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,26 @@
|
||||
using System;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Color
|
||||
namespace Artemis.VisualScripting.Nodes.Color;
|
||||
|
||||
[Node("Desaturate Color", "Desaturates a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||
public class DesaturateSKColorNode : Node
|
||||
{
|
||||
[Node("Desaturate Color", "Desaturates a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||
public class DesaturateSKColorNode : Node
|
||||
public DesaturateSKColorNode() : base("Desaturate Color", "Desaturates a color by a specified amount in percent")
|
||||
{
|
||||
public DesaturateSKColorNode() : base("Desaturate Color", "Desaturates a color by a specified amount in percent")
|
||||
{
|
||||
Input = CreateInputPin<SKColor>("Color");
|
||||
Percentage = CreateInputPin<Numeric>("%");
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
}
|
||||
Input = CreateInputPin<SKColor>("Color");
|
||||
Percentage = CreateInputPin<Numeric>("%");
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
}
|
||||
|
||||
public InputPin<SKColor> Input { get; }
|
||||
public InputPin<Numeric> Percentage { get; }
|
||||
public OutputPin<SKColor> Output { get; set; }
|
||||
public InputPin<SKColor> Input { get; }
|
||||
public InputPin<Numeric> Percentage { get; }
|
||||
public OutputPin<SKColor> Output { get; set; }
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Input.Value.ToHsl(out float h, out float s, out float l);
|
||||
s -= s * (Percentage.Value / 100f);
|
||||
Output.Value = SKColor.FromHsl(h, Math.Clamp(s, 0f, 100f), l);
|
||||
}
|
||||
public override void Evaluate()
|
||||
{
|
||||
Input.Value.ToHsl(out float h, out float s, out float l);
|
||||
s -= s * (Percentage.Value / 100f);
|
||||
Output.Value = SKColor.FromHsl(h, Math.Clamp(s, 0f, 100f), l);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,31 @@
|
||||
using Artemis.Core;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Color
|
||||
namespace Artemis.VisualScripting.Nodes.Color;
|
||||
|
||||
[Node("HSL Color", "Creates a color from hue, saturation and lightness values", "Color", InputType = typeof(Numeric), OutputType = typeof(SKColor))]
|
||||
public class HslSKColorNode : Node
|
||||
{
|
||||
[Node("HSL Color", "Creates a color from hue, saturation and lightness values", "Color", InputType = typeof(Numeric), OutputType = typeof(SKColor))]
|
||||
public class HslSKColorNode : Node
|
||||
public HslSKColorNode() : base("HSL Color", "Creates a color from hue, saturation and lightness values")
|
||||
{
|
||||
public HslSKColorNode() : base("HSL Color", "Creates a color from hue, saturation and lightness values")
|
||||
{
|
||||
H = CreateInputPin<Numeric>("H");
|
||||
S = CreateInputPin<Numeric>("S");
|
||||
L = CreateInputPin<Numeric>("L");
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
}
|
||||
|
||||
public InputPin<Numeric> H { get; set; }
|
||||
public InputPin<Numeric> S { get; set; }
|
||||
public InputPin<Numeric> L { get; set; }
|
||||
public OutputPin<SKColor> Output { get; }
|
||||
|
||||
#region Overrides of Node
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Evaluate()
|
||||
{
|
||||
Output.Value = SKColor.FromHsl(H.Value, S.Value, L.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
H = CreateInputPin<Numeric>("H");
|
||||
S = CreateInputPin<Numeric>("S");
|
||||
L = CreateInputPin<Numeric>("L");
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
}
|
||||
|
||||
public InputPin<Numeric> H { get; set; }
|
||||
public InputPin<Numeric> S { get; set; }
|
||||
public InputPin<Numeric> L { get; set; }
|
||||
public OutputPin<SKColor> Output { get; }
|
||||
|
||||
#region Overrides of Node
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Evaluate()
|
||||
{
|
||||
Output.Value = SKColor.FromHsl(H.Value, S.Value, L.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,28 +1,27 @@
|
||||
using Artemis.Core;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Color
|
||||
namespace Artemis.VisualScripting.Nodes.Color;
|
||||
|
||||
[Node("Invert Color", "Inverts a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||
public class InvertSKColorNode : Node
|
||||
{
|
||||
[Node("Invert Color", "Inverts a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||
public class InvertSKColorNode : Node
|
||||
public InvertSKColorNode() : base("Invert Color", "Inverts a color")
|
||||
{
|
||||
public InvertSKColorNode() : base("Invert Color", "Inverts a color")
|
||||
{
|
||||
Input = CreateInputPin<SKColor>();
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
}
|
||||
Input = CreateInputPin<SKColor>();
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
}
|
||||
|
||||
public InputPin<SKColor> Input { get; }
|
||||
public OutputPin<SKColor> Output { get; set; }
|
||||
public InputPin<SKColor> Input { get; }
|
||||
public OutputPin<SKColor> Output { get; set; }
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Output.Value = new SKColor(
|
||||
(byte) (255 - Input.Value.Red),
|
||||
(byte) (255 - Input.Value.Green),
|
||||
(byte) (255 - Input.Value.Blue),
|
||||
Input.Value.Alpha
|
||||
);
|
||||
}
|
||||
public override void Evaluate()
|
||||
{
|
||||
Output.Value = new SKColor(
|
||||
(byte) (255 - Input.Value.Red),
|
||||
(byte) (255 - Input.Value.Green),
|
||||
(byte) (255 - Input.Value.Blue),
|
||||
Input.Value.Alpha
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,26 @@
|
||||
using Artemis.Core;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Color
|
||||
namespace Artemis.VisualScripting.Nodes.Color;
|
||||
|
||||
[Node("Rotate Color Hue", "Rotates the hue of a color by a specified amount in degrees", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||
public class RotateHueSKColorNode : Node
|
||||
{
|
||||
[Node("Rotate Color Hue", "Rotates the hue of a color by a specified amount in degrees", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||
public class RotateHueSKColorNode : Node
|
||||
public RotateHueSKColorNode() : base("Rotate Color Hue", "Rotates the hue of a color by a specified amount in degrees")
|
||||
{
|
||||
public RotateHueSKColorNode() : base("Rotate Color Hue", "Rotates the hue of a color by a specified amount in degrees")
|
||||
{
|
||||
Input = CreateInputPin<SKColor>("Color");
|
||||
Amount = CreateInputPin<Numeric>("Amount");
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
}
|
||||
Input = CreateInputPin<SKColor>("Color");
|
||||
Amount = CreateInputPin<Numeric>("Amount");
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
}
|
||||
|
||||
public InputPin<SKColor> Input { get; }
|
||||
public InputPin<Numeric> Amount { get; }
|
||||
public OutputPin<SKColor> Output { get; set; }
|
||||
public InputPin<SKColor> Input { get; }
|
||||
public InputPin<Numeric> Amount { get; }
|
||||
public OutputPin<SKColor> Output { get; set; }
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Input.Value.ToHsl(out float h, out float s, out float l);
|
||||
h += Amount.Value;
|
||||
Output.Value = SKColor.FromHsl(h % 360, s, l);
|
||||
}
|
||||
public override void Evaluate()
|
||||
{
|
||||
Input.Value.ToHsl(out float h, out float s, out float l);
|
||||
h += Amount.Value;
|
||||
Output.Value = SKColor.FromHsl(h % 360, s, l);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,26 @@
|
||||
using System;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Color
|
||||
namespace Artemis.VisualScripting.Nodes.Color;
|
||||
|
||||
[Node("Saturate Color", "Saturates a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||
public class SaturateSKColorNode : Node
|
||||
{
|
||||
[Node("Saturate Color", "Saturates a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||
public class SaturateSKColorNode : Node
|
||||
public SaturateSKColorNode() : base("Saturate Color", "Saturates a color by a specified amount in percent")
|
||||
{
|
||||
public SaturateSKColorNode() : base("Saturate Color", "Saturates a color by a specified amount in percent")
|
||||
{
|
||||
Input = CreateInputPin<SKColor>("Color");
|
||||
Percentage = CreateInputPin<Numeric>("%");
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
}
|
||||
Input = CreateInputPin<SKColor>("Color");
|
||||
Percentage = CreateInputPin<Numeric>("%");
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
}
|
||||
|
||||
public InputPin<SKColor> Input { get; }
|
||||
public InputPin<Numeric> Percentage { get; }
|
||||
public OutputPin<SKColor> Output { get; set; }
|
||||
public InputPin<SKColor> Input { get; }
|
||||
public InputPin<Numeric> Percentage { get; }
|
||||
public OutputPin<SKColor> Output { get; set; }
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Input.Value.ToHsl(out float h, out float s, out float l);
|
||||
s += s * (Percentage.Value / 100f);
|
||||
Output.Value = SKColor.FromHsl(h, Math.Clamp(s, 0f, 100f), l);
|
||||
}
|
||||
public override void Evaluate()
|
||||
{
|
||||
Input.Value.ToHsl(out float h, out float s, out float l);
|
||||
s += s * (Percentage.Value / 100f);
|
||||
Output.Value = SKColor.FromHsl(h, Math.Clamp(s, 0f, 100f), l);
|
||||
}
|
||||
}
|
||||
@@ -2,34 +2,33 @@
|
||||
using Artemis.VisualScripting.Nodes.Color.CustomViewModels;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Color
|
||||
namespace Artemis.VisualScripting.Nodes.Color;
|
||||
|
||||
[Node("Color-Value", "Outputs a configurable color value.", "Static", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||
public class StaticSKColorValueNode : Node<SKColor, StaticSKColorValueNodeCustomViewModel>
|
||||
{
|
||||
[Node("Color-Value", "Outputs a configurable color value.", "Static", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||
public class StaticSKColorValueNode : Node<SKColor, StaticSKColorValueNodeCustomViewModel>
|
||||
#region Constructors
|
||||
|
||||
public StaticSKColorValueNode()
|
||||
: base("Color", "Outputs a configurable color value.")
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public StaticSKColorValueNode()
|
||||
: base("Color", "Outputs a configurable color value.")
|
||||
{
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public OutputPin<SKColor> Output { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Output.Value = Storage;
|
||||
}
|
||||
|
||||
#endregion
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public OutputPin<SKColor> Output { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Output.Value = Storage;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,46 +1,45 @@
|
||||
using Artemis.Core;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Color
|
||||
namespace Artemis.VisualScripting.Nodes.Color;
|
||||
|
||||
[Node("Sum (Color)", "Sums the connected color values.", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||
public class SumSKColorsNode : Node
|
||||
{
|
||||
[Node("Sum (Color)", "Sums the connected color values.", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||
public class SumSKColorsNode : Node
|
||||
#region Constructors
|
||||
|
||||
public SumSKColorsNode()
|
||||
: base("Sum", "Sums the connected color values.")
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPinCollection<SKColor> Values { get; }
|
||||
|
||||
public OutputPin<SKColor> Sum { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public SumSKColorsNode()
|
||||
: base("Sum", "Sums the connected color values.")
|
||||
{
|
||||
Values = CreateInputPinCollection<SKColor>("Values", 2);
|
||||
Sum = CreateOutputPin<SKColor>("Sum");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
SKColor result = SKColor.Empty;
|
||||
|
||||
bool first = true;
|
||||
foreach (SKColor current in Values.Values)
|
||||
{
|
||||
result = first ? current : result.Sum(current);
|
||||
first = false;
|
||||
}
|
||||
|
||||
Sum.Value = result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
Values = CreateInputPinCollection<SKColor>("Values", 2);
|
||||
Sum = CreateOutputPin<SKColor>("Sum");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
SKColor result = SKColor.Empty;
|
||||
|
||||
bool first = true;
|
||||
foreach (SKColor current in Values.Values)
|
||||
{
|
||||
result = first ? current : result.Sum(current);
|
||||
first = false;
|
||||
}
|
||||
|
||||
Sum.Value = result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPinCollection<SKColor> Values { get; }
|
||||
|
||||
public OutputPin<SKColor> Sum { get; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,81 +1,80 @@
|
||||
using Artemis.Core;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes
|
||||
namespace Artemis.VisualScripting.Nodes;
|
||||
|
||||
[Node("To String", "Converts the input to a string.", "Conversion", InputType = typeof(object), OutputType = typeof(string))]
|
||||
public class ConvertToStringNode : Node
|
||||
{
|
||||
[Node("To String", "Converts the input to a string.", "Conversion", InputType = typeof(object), OutputType = typeof(string))]
|
||||
public class ConvertToStringNode : Node
|
||||
#region Constructors
|
||||
|
||||
public ConvertToStringNode()
|
||||
: base("To String", "Converts the input to a string.")
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPin<object> Input { get; }
|
||||
|
||||
public OutputPin<string> String { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public ConvertToStringNode()
|
||||
: base("To String", "Converts the input to a string.")
|
||||
{
|
||||
Input = CreateInputPin<object>();
|
||||
String = CreateOutputPin<string>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
String.Value = Input.Value?.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
Input = CreateInputPin<object>();
|
||||
String = CreateOutputPin<string>();
|
||||
}
|
||||
|
||||
[Node("To Numeric", "Converts the input to a numeric.", "Conversion", InputType = typeof(object), OutputType = typeof(Numeric))]
|
||||
public class ConvertToNumericNode : Node
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPin<object> Input { get; }
|
||||
|
||||
public OutputPin<Numeric> Output { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public ConvertToNumericNode()
|
||||
: base("To Numeric", "Converts the input to a numeric.")
|
||||
{
|
||||
Input = CreateInputPin<object>();
|
||||
Output = CreateOutputPin<Numeric>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Output.Value = Input.Value switch
|
||||
{
|
||||
int input => new Numeric(input),
|
||||
double input => new Numeric(input),
|
||||
float input => new Numeric(input),
|
||||
byte input => new Numeric(input),
|
||||
_ => TryParse(Input.Value)
|
||||
};
|
||||
}
|
||||
|
||||
private Numeric TryParse(object input)
|
||||
{
|
||||
Numeric.TryParse(input?.ToString(), out Numeric value);
|
||||
return value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
String.Value = Input.Value?.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPin<object> Input { get; }
|
||||
|
||||
public OutputPin<string> String { get; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Node("To Numeric", "Converts the input to a numeric.", "Conversion", InputType = typeof(object), OutputType = typeof(Numeric))]
|
||||
public class ConvertToNumericNode : Node
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public ConvertToNumericNode()
|
||||
: base("To Numeric", "Converts the input to a numeric.")
|
||||
{
|
||||
Input = CreateInputPin<object>();
|
||||
Output = CreateOutputPin<Numeric>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPin<object> Input { get; }
|
||||
|
||||
public OutputPin<Numeric> Output { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Output.Value = Input.Value switch
|
||||
{
|
||||
int input => new Numeric(input),
|
||||
double input => new Numeric(input),
|
||||
float input => new Numeric(input),
|
||||
byte input => new Numeric(input),
|
||||
_ => TryParse(Input.Value)
|
||||
};
|
||||
}
|
||||
|
||||
private Numeric TryParse(object input)
|
||||
{
|
||||
Numeric.TryParse(input?.ToString(), out Numeric value);
|
||||
return value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Artemis.Core;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.CustomViewModels
|
||||
{
|
||||
public abstract class CustomNodeViewModel : PropertyChangedBase, ICustomNodeViewModel
|
||||
{
|
||||
protected CustomNodeViewModel(INode node)
|
||||
{
|
||||
Node = node;
|
||||
}
|
||||
|
||||
public INode Node { get; }
|
||||
|
||||
#region Implementation of ICustomNodeViewModel
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void OnActivate()
|
||||
{
|
||||
Node.PropertyChanged += NodeOnPropertyChanged;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void OnDeactivate()
|
||||
{
|
||||
Node.PropertyChanged -= NodeOnPropertyChanged;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler NodeModified;
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="NodeModified"/> event
|
||||
/// </summary>
|
||||
protected virtual void OnNodeModified()
|
||||
{
|
||||
NodeModified?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void NodeOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == "Storage")
|
||||
OnNodeModified();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
+38
-38
@@ -1,49 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Events;
|
||||
using Stylet;
|
||||
using Artemis.UI.Shared.VisualScripting;
|
||||
using DynamicData;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.CustomViewModels
|
||||
namespace Artemis.VisualScripting.Nodes.CustomViewModels;
|
||||
|
||||
public class EnumEqualsNodeCustomViewModel : CustomNodeViewModel
|
||||
{
|
||||
public class EnumEqualsNodeCustomViewModel : CustomNodeViewModel
|
||||
private readonly EnumEqualsNode _node;
|
||||
|
||||
public EnumEqualsNodeCustomViewModel(EnumEqualsNode node, INodeScript script) : base(node, script)
|
||||
{
|
||||
private readonly EnumEqualsNode _node;
|
||||
_node = node;
|
||||
}
|
||||
|
||||
public EnumEqualsNodeCustomViewModel(EnumEqualsNode node) : base(node)
|
||||
{
|
||||
_node = node;
|
||||
}
|
||||
public ObservableCollection<(Enum, string)> EnumValues { get; } = new();
|
||||
|
||||
public BindableCollection<(Enum, string)> EnumValues { get; } = new();
|
||||
// public override void OnActivate()
|
||||
// {
|
||||
// _node.InputPin.PinConnected += InputPinOnPinConnected;
|
||||
// _node.InputPin.PinDisconnected += InputPinOnPinDisconnected;
|
||||
//
|
||||
// if (_node.InputPin.Value != null && _node.InputPin.Value.GetType().IsEnum)
|
||||
// EnumValues.AddRange(EnumUtilities.GetAllValuesAndDescriptions(_node.InputPin.Value.GetType()));
|
||||
// base.OnActivate();
|
||||
// }
|
||||
//
|
||||
// public override void OnDeactivate()
|
||||
// {
|
||||
// _node.InputPin.PinConnected -= InputPinOnPinConnected;
|
||||
// _node.InputPin.PinDisconnected -= InputPinOnPinDisconnected;
|
||||
//
|
||||
// base.OnDeactivate();
|
||||
// }
|
||||
|
||||
public override void OnActivate()
|
||||
{
|
||||
_node.InputPin.PinConnected += InputPinOnPinConnected;
|
||||
_node.InputPin.PinDisconnected += InputPinOnPinDisconnected;
|
||||
private void InputPinOnPinDisconnected(object sender, SingleValueEventArgs<IPin> e)
|
||||
{
|
||||
EnumValues.Clear();
|
||||
}
|
||||
|
||||
if (_node.InputPin.Value != null && _node.InputPin.Value.GetType().IsEnum)
|
||||
EnumValues.AddRange(EnumUtilities.GetAllValuesAndDescriptions(_node.InputPin.Value.GetType()));
|
||||
base.OnActivate();
|
||||
}
|
||||
|
||||
public override void OnDeactivate()
|
||||
{
|
||||
_node.InputPin.PinConnected -= InputPinOnPinConnected;
|
||||
_node.InputPin.PinDisconnected -= InputPinOnPinDisconnected;
|
||||
|
||||
base.OnDeactivate();
|
||||
}
|
||||
|
||||
private void InputPinOnPinDisconnected(object sender, SingleValueEventArgs<IPin> e)
|
||||
{
|
||||
EnumValues.Clear();
|
||||
}
|
||||
|
||||
private void InputPinOnPinConnected(object sender, SingleValueEventArgs<IPin> e)
|
||||
{
|
||||
EnumValues.Clear();
|
||||
if (_node.InputPin.Value != null && _node.InputPin.Value.GetType().IsEnum)
|
||||
EnumValues.AddRange(EnumUtilities.GetAllValuesAndDescriptions(_node.InputPin.Value.GetType()));
|
||||
}
|
||||
private void InputPinOnPinConnected(object sender, SingleValueEventArgs<IPin> e)
|
||||
{
|
||||
EnumValues.Clear();
|
||||
if (_node.InputPin.Value != null && _node.InputPin.Value.GetType().IsEnum)
|
||||
EnumValues.AddRange(EnumUtilities.GetAllValuesAndDescriptions(_node.InputPin.Value.GetType()));
|
||||
}
|
||||
}
|
||||
+67
-74
@@ -1,80 +1,73 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Collections.ObjectModel;
|
||||
using Artemis.Core;
|
||||
using Stylet;
|
||||
using Artemis.UI.Shared.VisualScripting;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.CustomViewModels
|
||||
namespace Artemis.VisualScripting.Nodes.CustomViewModels;
|
||||
|
||||
public class LayerPropertyNodeCustomViewModel : CustomNodeViewModel
|
||||
{
|
||||
public class LayerPropertyNodeCustomViewModel : CustomNodeViewModel
|
||||
private readonly LayerPropertyNode _node;
|
||||
private ILayerProperty _selectedLayerProperty;
|
||||
|
||||
private RenderProfileElement _selectedProfileElement;
|
||||
|
||||
public LayerPropertyNodeCustomViewModel(LayerPropertyNode node, INodeScript script) : base(node, script)
|
||||
{
|
||||
private readonly LayerPropertyNode _node;
|
||||
|
||||
private RenderProfileElement _selectedProfileElement;
|
||||
private ILayerProperty _selectedLayerProperty;
|
||||
|
||||
public LayerPropertyNodeCustomViewModel(LayerPropertyNode node) : base(node)
|
||||
{
|
||||
_node = node;
|
||||
}
|
||||
|
||||
public BindableCollection<RenderProfileElement> ProfileElements { get; } = new();
|
||||
|
||||
public RenderProfileElement SelectedProfileElement
|
||||
{
|
||||
get => _selectedProfileElement;
|
||||
set
|
||||
{
|
||||
if (!SetAndNotify(ref _selectedProfileElement, value)) return;
|
||||
_node.ChangeProfileElement(_selectedProfileElement);
|
||||
GetLayerProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public BindableCollection<ILayerProperty> LayerProperties { get; } = new();
|
||||
|
||||
public ILayerProperty SelectedLayerProperty
|
||||
{
|
||||
get => _selectedLayerProperty;
|
||||
set
|
||||
{
|
||||
if (!SetAndNotify(ref _selectedLayerProperty, value)) return;
|
||||
_node.ChangeLayerProperty(_selectedLayerProperty);
|
||||
}
|
||||
}
|
||||
|
||||
private void GetProfileElements()
|
||||
{
|
||||
ProfileElements.Clear();
|
||||
if (_node.Script.Context is not Profile profile)
|
||||
return;
|
||||
|
||||
List<RenderProfileElement> elements = new(profile.GetAllRenderElements());
|
||||
|
||||
ProfileElements.AddRange(elements.OrderBy(e => e.Order));
|
||||
_selectedProfileElement = _node.ProfileElement;
|
||||
NotifyOfPropertyChange(nameof(SelectedProfileElement));
|
||||
}
|
||||
|
||||
private void GetLayerProperties()
|
||||
{
|
||||
LayerProperties.Clear();
|
||||
if (_node.ProfileElement == null)
|
||||
return;
|
||||
|
||||
LayerProperties.AddRange(_node.ProfileElement.GetAllLayerProperties().Where(l => !l.IsHidden && l.DataBindingsSupported));
|
||||
_selectedLayerProperty = _node.LayerProperty;
|
||||
NotifyOfPropertyChange(nameof(SelectedLayerProperty));
|
||||
}
|
||||
|
||||
public override void OnActivate()
|
||||
{
|
||||
GetProfileElements();
|
||||
GetLayerProperties();
|
||||
}
|
||||
|
||||
public override void OnDeactivate()
|
||||
{
|
||||
base.OnDeactivate();
|
||||
}
|
||||
_node = node;
|
||||
}
|
||||
|
||||
public ObservableCollection<RenderProfileElement> ProfileElements { get; } = new();
|
||||
|
||||
// public RenderProfileElement SelectedProfileElement
|
||||
// {
|
||||
// get => _selectedProfileElement;
|
||||
// set
|
||||
// {
|
||||
// if (!SetAndNotify(ref _selectedProfileElement, value)) return;
|
||||
// _node.ChangeProfileElement(_selectedProfileElement);
|
||||
// GetLayerProperties();
|
||||
// }
|
||||
// }
|
||||
|
||||
public ObservableCollection<ILayerProperty> LayerProperties { get; } = new();
|
||||
|
||||
// public ILayerProperty SelectedLayerProperty
|
||||
// {
|
||||
// get => _selectedLayerProperty;
|
||||
// set
|
||||
// {
|
||||
// if (!SetAndNotify(ref _selectedLayerProperty, value)) return;
|
||||
// _node.ChangeLayerProperty(_selectedLayerProperty);
|
||||
// }
|
||||
// }
|
||||
|
||||
// private void GetProfileElements()
|
||||
// {
|
||||
// ProfileElements.Clear();
|
||||
// if (_node.Script.Context is not Profile profile)
|
||||
// return;
|
||||
//
|
||||
// List<RenderProfileElement> elements = new(profile.GetAllRenderElements());
|
||||
//
|
||||
// ProfileElements.AddRange(elements.OrderBy(e => e.Order));
|
||||
// _selectedProfileElement = _node.ProfileElement;
|
||||
// NotifyOfPropertyChange(nameof(SelectedProfileElement));
|
||||
// }
|
||||
//
|
||||
// private void GetLayerProperties()
|
||||
// {
|
||||
// LayerProperties.Clear();
|
||||
// if (_node.ProfileElement == null)
|
||||
// return;
|
||||
//
|
||||
// LayerProperties.AddRange(_node.ProfileElement.GetAllLayerProperties().Where(l => !l.IsHidden && l.DataBindingsSupported));
|
||||
// _selectedLayerProperty = _node.LayerProperty;
|
||||
// NotifyOfPropertyChange(nameof(SelectedLayerProperty));
|
||||
// }
|
||||
//
|
||||
// public override void OnActivate()
|
||||
// {
|
||||
// GetProfileElements();
|
||||
// GetLayerProperties();
|
||||
// }
|
||||
}
|
||||
@@ -1,18 +1,47 @@
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared.Services.NodeEditor;
|
||||
using Artemis.UI.Shared.Services.NodeEditor.Commands;
|
||||
using Artemis.UI.Shared.VisualScripting;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.CustomViewModels
|
||||
namespace Artemis.VisualScripting.Nodes.CustomViewModels;
|
||||
|
||||
public class StaticNumericValueNodeCustomViewModel : CustomNodeViewModel
|
||||
{
|
||||
public class StaticNumericValueNodeCustomViewModel : CustomNodeViewModel
|
||||
private readonly StaticNumericValueNode _node;
|
||||
private readonly INodeEditorService _nodeEditorService;
|
||||
|
||||
public StaticNumericValueNodeCustomViewModel(StaticNumericValueNode node, INodeScript script, INodeEditorService nodeEditorService) : base(node, script)
|
||||
{
|
||||
public StaticNumericValueNodeCustomViewModel(INode node) : base(node)
|
||||
{
|
||||
}
|
||||
_node = node;
|
||||
_nodeEditorService = nodeEditorService;
|
||||
|
||||
NodeModified += (_, _) => this.RaisePropertyChanged(nameof(CurrentValue));
|
||||
}
|
||||
|
||||
public class StaticStringValueNodeCustomViewModel : CustomNodeViewModel
|
||||
public Numeric? CurrentValue
|
||||
{
|
||||
public StaticStringValueNodeCustomViewModel(INode node) : base(node)
|
||||
{
|
||||
}
|
||||
get => _node.Storage;
|
||||
set => _nodeEditorService.ExecuteCommand(Script, new UpdateStorage<Numeric>(_node, value ?? new Numeric()));
|
||||
}
|
||||
}
|
||||
|
||||
public class StaticStringValueNodeCustomViewModel : CustomNodeViewModel
|
||||
{
|
||||
private readonly StaticStringValueNode _node;
|
||||
private readonly INodeEditorService _nodeEditorService;
|
||||
|
||||
public StaticStringValueNodeCustomViewModel(StaticStringValueNode node, INodeScript script, INodeEditorService nodeEditorService) : base(node, script)
|
||||
{
|
||||
_node = node;
|
||||
_nodeEditorService = nodeEditorService;
|
||||
|
||||
NodeModified += (_, _) => this.RaisePropertyChanged(nameof(CurrentValue));
|
||||
}
|
||||
|
||||
public string? CurrentValue
|
||||
{
|
||||
get => _node.Storage;
|
||||
set => _nodeEditorService.ExecuteCommand(Script, new UpdateStorage<string>(_node, value));
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<UserControl x:Class="Artemis.VisualScripting.Nodes.CustomViews.EnumEqualsNodeCustomView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.VisualScripting.Nodes.CustomViews"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<ComboBox Width="140"
|
||||
materialDesign:ComboBoxAssist.ClassicMode="True"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Stretch"
|
||||
SelectedValue="{Binding Node.Storage}"
|
||||
ItemsSource="{Binding EnumValues}"
|
||||
SelectedValuePath="Value"
|
||||
DisplayMemberPath="Description">
|
||||
<ComboBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ComboBox.ItemsPanel>
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,18 +0,0 @@
|
||||
<UserControl x:Class="Artemis.VisualScripting.Nodes.CustomViews.LayerPropertyNodeCustomView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.VisualScripting.Nodes.CustomViews"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<StackPanel>
|
||||
<ComboBox Margin="8 0"
|
||||
ItemsSource="{Binding ProfileElements}"
|
||||
SelectedValue="{Binding SelectedProfileElement}" />
|
||||
<ComboBox Margin="8 0"
|
||||
ItemsSource="{Binding LayerProperties}"
|
||||
SelectedValue="{Binding SelectedLayerProperty}"
|
||||
DisplayMemberPath="PropertyDescription.Name"/>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,20 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:customViewModels="clr-namespace:Artemis.VisualScripting.Nodes.CustomViewModels"
|
||||
xmlns:converters="clr-namespace:Artemis.VisualScripting.Converters"
|
||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:behaviors="clr-namespace:Artemis.UI.Shared.Behaviors;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.VisualScripting.Nodes.CustomViews.StaticNumericValueNodeCustomView"
|
||||
x:DataType="customViewModels:StaticNumericValueNodeCustomViewModel">
|
||||
<UserControl.Resources>
|
||||
<converters:NumericConverter x:Key="NumericConverter" />
|
||||
</UserControl.Resources>
|
||||
<controls:NumberBox VerticalAlignment="Center" MinWidth="75" SimpleNumberFormat="F3" Classes="condensed">
|
||||
<Interaction.Behaviors>
|
||||
<behaviors:LostFocusNumberBoxBindingBehavior Value="{CompiledBinding CurrentValue, Converter={StaticResource NumericConverter}}"/>
|
||||
</Interaction.Behaviors>
|
||||
</controls:NumberBox>
|
||||
</UserControl>
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
using Artemis.VisualScripting.Nodes.CustomViewModels;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.CustomViews
|
||||
{
|
||||
public partial class StaticNumericValueNodeCustomView : ReactiveUserControl<StaticNumericValueNodeCustomViewModel>
|
||||
{
|
||||
public StaticNumericValueNodeCustomView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<UserControl x:Class="Artemis.VisualScripting.Nodes.CustomViews.StaticNumericValueNodeCustomView"
|
||||
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:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<shared:StringToNumericConverter x:Key="StringToNumericConverter"/>
|
||||
</UserControl.Resources>
|
||||
<TextBox VerticalAlignment="Center"
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding Node.Storage, Converter={StaticResource StringToNumericConverter}}" />
|
||||
</UserControl>
|
||||
@@ -0,0 +1,15 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:customViewModels="clr-namespace:Artemis.VisualScripting.Nodes.CustomViewModels"
|
||||
xmlns:behaviors="clr-namespace:Artemis.UI.Shared.Behaviors;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.VisualScripting.Nodes.CustomViews.StaticStringValueNodeCustomView"
|
||||
x:DataType="customViewModels:StaticStringValueNodeCustomViewModel">
|
||||
<TextBox VerticalAlignment="Center" MinWidth="75" Classes="condensed">
|
||||
<Interaction.Behaviors>
|
||||
<behaviors:LostFocusTextBoxBindingBehavior Text="{CompiledBinding CurrentValue}"/>
|
||||
</Interaction.Behaviors>
|
||||
</TextBox>
|
||||
</UserControl>
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
using Artemis.VisualScripting.Nodes.CustomViewModels;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.CustomViews
|
||||
{
|
||||
public partial class StaticStringValueNodeCustomView : ReactiveUserControl<StaticStringValueNodeCustomViewModel>
|
||||
{
|
||||
public StaticStringValueNodeCustomView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
<UserControl x:Class="Artemis.VisualScripting.Nodes.CustomViews.StaticStringValueNodeCustomView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.VisualScripting.Nodes.CustomViewModels"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<TextBox VerticalAlignment="Center"
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding Node.Storage}" />
|
||||
</UserControl>
|
||||
+79
-49
@@ -1,75 +1,105 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reactive.Disposables;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.VisualScripting.Nodes.CustomViewModels;
|
||||
using Stylet;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Artemis.UI.Shared.Services.NodeEditor;
|
||||
using Artemis.UI.Shared.Services.NodeEditor.Commands;
|
||||
using Artemis.UI.Shared.VisualScripting;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.DataModel.CustomViewModels
|
||||
namespace Artemis.VisualScripting.Nodes.DataModel.CustomViewModels;
|
||||
|
||||
public class DataModelEventNodeCustomViewModel : CustomNodeViewModel
|
||||
{
|
||||
public class DataModelEventNodeCustomViewModel : CustomNodeViewModel
|
||||
private readonly DataModelEventNode _node;
|
||||
private readonly INodeEditorService _nodeEditorService;
|
||||
private bool _updating;
|
||||
private DataModelPath? _dataModelPath;
|
||||
private ObservableCollection<Module>? _modules;
|
||||
|
||||
public DataModelEventNodeCustomViewModel(DataModelEventNode node, INodeScript script, ISettingsService settingsService, INodeEditorService nodeEditorService) : base(node, script)
|
||||
{
|
||||
private readonly DataModelEventNode _node;
|
||||
private BindableCollection<Module> _modules;
|
||||
_node = node;
|
||||
_nodeEditorService = nodeEditorService;
|
||||
|
||||
public DataModelEventNodeCustomViewModel(DataModelEventNode node, ISettingsService settingsService) : base(node)
|
||||
ShowFullPaths = settingsService.GetSetting("ProfileEditor.ShowFullPaths", true);
|
||||
ShowDataModelValues = settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false);
|
||||
Modules = new ObservableCollection<Module>();
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
_node = node;
|
||||
// Set up extra modules
|
||||
if (_node.Script?.Context is Profile scriptProfile && scriptProfile.Configuration.Module != null)
|
||||
Modules = new ObservableCollection<Module> {scriptProfile.Configuration.Module};
|
||||
else if (_node.Script?.Context is ProfileConfiguration profileConfiguration && profileConfiguration.Module != null)
|
||||
Modules = new ObservableCollection<Module> {profileConfiguration.Module};
|
||||
|
||||
ShowFullPaths = settingsService.GetSetting("ProfileEditor.ShowFullPaths", true);
|
||||
ShowDataModelValues = settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false);
|
||||
}
|
||||
// Subscribe to node changes
|
||||
_node.WhenAnyValue(n => n.Storage).Subscribe(UpdateDataModelPath).DisposeWith(d);
|
||||
this.WhenAnyValue(vm => vm.DataModelPath).Subscribe(ApplyDataModelPath).DisposeWith(d);
|
||||
|
||||
public PluginSetting<bool> ShowFullPaths { get; }
|
||||
public PluginSetting<bool> ShowDataModelValues { get; }
|
||||
public BindableCollection<Type> FilterTypes { get; } = new() { typeof(IDataModelEvent) };
|
||||
|
||||
public BindableCollection<Module> Modules
|
||||
{
|
||||
get => _modules;
|
||||
set => SetAndNotify(ref _modules, value);
|
||||
}
|
||||
|
||||
public DataModelPath DataModelPath
|
||||
{
|
||||
get => _node.DataModelPath;
|
||||
set
|
||||
Disposable.Create(() =>
|
||||
{
|
||||
if (ReferenceEquals(_node.DataModelPath, value))
|
||||
return;
|
||||
_dataModelPath?.Dispose();
|
||||
_dataModelPath = null;
|
||||
}).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
_node.DataModelPath?.Dispose();
|
||||
_node.DataModelPath = value;
|
||||
_node.DataModelPath.Save();
|
||||
public PluginSetting<bool> ShowFullPaths { get; }
|
||||
public PluginSetting<bool> ShowDataModelValues { get; }
|
||||
public ObservableCollection<Type> FilterTypes { get; } = new() {typeof(IDataModelEvent)};
|
||||
|
||||
_node.Storage = _node.DataModelPath.Entity;
|
||||
}
|
||||
}
|
||||
public ObservableCollection<Module>? Modules
|
||||
{
|
||||
get => _modules;
|
||||
set => RaiseAndSetIfChanged(ref _modules, value);
|
||||
}
|
||||
|
||||
public override void OnActivate()
|
||||
public DataModelPath? DataModelPath
|
||||
{
|
||||
get => _dataModelPath;
|
||||
set => RaiseAndSetIfChanged(ref _dataModelPath, value);
|
||||
}
|
||||
|
||||
private void UpdateDataModelPath(DataModelPathEntity? entity)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Modules != null)
|
||||
if (_updating)
|
||||
return;
|
||||
|
||||
Modules = new BindableCollection<Module>();
|
||||
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)
|
||||
Modules.Add(profileConfiguration.Module);
|
||||
_updating = true;
|
||||
|
||||
_node.PropertyChanged += NodeOnPropertyChanged;
|
||||
DataModelPath? old = DataModelPath;
|
||||
DataModelPath = entity != null ? new DataModelPath(entity) : null;
|
||||
old?.Dispose();
|
||||
}
|
||||
|
||||
public override void OnDeactivate()
|
||||
finally
|
||||
{
|
||||
_node.PropertyChanged -= NodeOnPropertyChanged;
|
||||
_updating = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void NodeOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
private void ApplyDataModelPath(DataModelPath? path)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.PropertyName == nameof(DataModelNode.DataModelPath))
|
||||
OnPropertyChanged(nameof(DataModelPath));
|
||||
if (_updating)
|
||||
return;
|
||||
if (path?.Path == _node.Storage?.Path)
|
||||
return;
|
||||
|
||||
_updating = true;
|
||||
|
||||
path?.Save();
|
||||
_nodeEditorService.ExecuteCommand(Script, new UpdateStorage<DataModelPathEntity>(_node, path?.Entity, "event"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
_updating = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+78
-48
@@ -1,74 +1,104 @@
|
||||
using System.ComponentModel;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Reactive.Disposables;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.VisualScripting.Nodes.CustomViewModels;
|
||||
using Stylet;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Artemis.UI.Shared.Services.NodeEditor;
|
||||
using Artemis.UI.Shared.Services.NodeEditor.Commands;
|
||||
using Artemis.UI.Shared.VisualScripting;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.DataModel.CustomViewModels
|
||||
namespace Artemis.VisualScripting.Nodes.DataModel.CustomViewModels;
|
||||
|
||||
public class DataModelNodeCustomViewModel : CustomNodeViewModel
|
||||
{
|
||||
public class DataModelNodeCustomViewModel : CustomNodeViewModel
|
||||
private readonly DataModelNode _node;
|
||||
private readonly INodeEditorService _nodeEditorService;
|
||||
private ObservableCollection<Module>? _modules;
|
||||
private DataModelPath? _dataModelPath;
|
||||
private bool _updating;
|
||||
|
||||
public DataModelNodeCustomViewModel(DataModelNode node, INodeScript script, ISettingsService settingsService, INodeEditorService nodeEditorService) : base(node, script)
|
||||
{
|
||||
private readonly DataModelNode _node;
|
||||
private BindableCollection<Module> _modules;
|
||||
_node = node;
|
||||
_nodeEditorService = nodeEditorService;
|
||||
|
||||
public DataModelNodeCustomViewModel(DataModelNode node, ISettingsService settingsService) : base(node)
|
||||
ShowFullPaths = settingsService.GetSetting("ProfileEditor.ShowFullPaths", true);
|
||||
ShowDataModelValues = settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false);
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
_node = node;
|
||||
// Set up extra modules
|
||||
if (_node.Script?.Context is Profile scriptProfile && scriptProfile.Configuration.Module != null)
|
||||
Modules = new ObservableCollection<Module> {scriptProfile.Configuration.Module};
|
||||
else if (_node.Script?.Context is ProfileConfiguration profileConfiguration && profileConfiguration.Module != null)
|
||||
Modules = new ObservableCollection<Module> {profileConfiguration.Module};
|
||||
|
||||
ShowFullPaths = settingsService.GetSetting("ProfileEditor.ShowFullPaths", true);
|
||||
ShowDataModelValues = settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false);
|
||||
}
|
||||
// Subscribe to node changes
|
||||
_node.WhenAnyValue(n => n.Storage).Subscribe(UpdateDataModelPath).DisposeWith(d);
|
||||
this.WhenAnyValue(vm => vm.DataModelPath).Subscribe(ApplyDataModelPath).DisposeWith(d);
|
||||
|
||||
public PluginSetting<bool> ShowFullPaths { get; }
|
||||
public PluginSetting<bool> ShowDataModelValues { get; }
|
||||
|
||||
public BindableCollection<Module> Modules
|
||||
{
|
||||
get => _modules;
|
||||
set => SetAndNotify(ref _modules, value);
|
||||
}
|
||||
|
||||
public DataModelPath DataModelPath
|
||||
{
|
||||
get => _node.DataModelPath;
|
||||
set
|
||||
Disposable.Create(() =>
|
||||
{
|
||||
if (ReferenceEquals(_node.DataModelPath, value))
|
||||
return;
|
||||
_dataModelPath?.Dispose();
|
||||
_dataModelPath = null;
|
||||
}).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
_node.DataModelPath?.Dispose();
|
||||
_node.DataModelPath = value;
|
||||
_node.DataModelPath.Save();
|
||||
public PluginSetting<bool> ShowFullPaths { get; }
|
||||
public PluginSetting<bool> ShowDataModelValues { get; }
|
||||
|
||||
_node.Storage = _node.DataModelPath.Entity;
|
||||
_node.UpdateOutputPin(false);
|
||||
}
|
||||
}
|
||||
public ObservableCollection<Module>? Modules
|
||||
{
|
||||
get => _modules;
|
||||
set => RaiseAndSetIfChanged(ref _modules, value);
|
||||
}
|
||||
|
||||
public override void OnActivate()
|
||||
public DataModelPath? DataModelPath
|
||||
{
|
||||
get => _dataModelPath;
|
||||
set => RaiseAndSetIfChanged(ref _dataModelPath, value);
|
||||
}
|
||||
|
||||
private void UpdateDataModelPath(DataModelPathEntity? entity)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Modules != null)
|
||||
if (_updating)
|
||||
return;
|
||||
|
||||
Modules = new BindableCollection<Module>();
|
||||
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)
|
||||
Modules.Add(profileConfiguration.Module);
|
||||
_updating = true;
|
||||
|
||||
_node.PropertyChanged += NodeOnPropertyChanged;
|
||||
DataModelPath? old = DataModelPath;
|
||||
DataModelPath = entity != null ? new DataModelPath(entity) : null;
|
||||
old?.Dispose();
|
||||
}
|
||||
|
||||
public override void OnDeactivate()
|
||||
finally
|
||||
{
|
||||
_node.PropertyChanged -= NodeOnPropertyChanged;
|
||||
_updating = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void NodeOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
private void ApplyDataModelPath(DataModelPath? path)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.PropertyName == nameof(DataModelNode.DataModelPath))
|
||||
OnPropertyChanged(nameof(DataModelPath));
|
||||
if (_updating)
|
||||
return;
|
||||
if (path?.Path == _node.Storage?.Path)
|
||||
return;
|
||||
|
||||
_updating = true;
|
||||
|
||||
path?.Save();
|
||||
_nodeEditorService.ExecuteCommand(Script, new UpdateStorage<DataModelPathEntity>(_node, path?.Entity, "path"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
_updating = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:dataModelPicker="clr-namespace:Artemis.UI.Shared.Controls.DataModelPicker;assembly=Artemis.UI.Shared"
|
||||
xmlns:customViewModels="clr-namespace:Artemis.VisualScripting.Nodes.DataModel.CustomViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.VisualScripting.Nodes.DataModel.CustomViews.DataModelEventNodeCustomView"
|
||||
x:DataType="customViewModels:DataModelEventNodeCustomViewModel">
|
||||
<dataModelPicker:DataModelPickerButton Classes="condensed"
|
||||
DataModelPath="{CompiledBinding DataModelPath}"
|
||||
Modules="{CompiledBinding Modules}"
|
||||
ShowDataModelValues="{CompiledBinding ShowDataModelValues.Value}"
|
||||
FilterTypes="{CompiledBinding FilterTypes}"
|
||||
VerticalAlignment="Top"/>
|
||||
</UserControl>
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
using Artemis.VisualScripting.Nodes.DataModel.CustomViewModels;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.DataModel.CustomViews
|
||||
{
|
||||
public partial class DataModelEventNodeCustomView : ReactiveUserControl<DataModelEventNodeCustomViewModel>
|
||||
{
|
||||
public DataModelEventNodeCustomView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +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:local="clr-namespace:Artemis.VisualScripting.Nodes.CustomViews"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||
xmlns:editor="clr-namespace:Artemis.VisualScripting.Editor.Controls"
|
||||
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>
|
||||
@@ -0,0 +1,14 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:dataModelPicker="clr-namespace:Artemis.UI.Shared.Controls.DataModelPicker;assembly=Artemis.UI.Shared"
|
||||
xmlns:customViewModels="clr-namespace:Artemis.VisualScripting.Nodes.DataModel.CustomViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.VisualScripting.Nodes.DataModel.CustomViews.DataModelNodeCustomView"
|
||||
x:DataType="customViewModels:DataModelNodeCustomViewModel">
|
||||
<dataModelPicker:DataModelPickerButton Classes="condensed"
|
||||
DataModelPath="{CompiledBinding DataModelPath}"
|
||||
Modules="{CompiledBinding Modules}"
|
||||
ShowDataModelValues="{CompiledBinding ShowDataModelValues.Value}" />
|
||||
</UserControl>
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
using Artemis.VisualScripting.Nodes.DataModel.CustomViewModels;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.DataModel.CustomViews
|
||||
{
|
||||
public partial class DataModelNodeCustomView : ReactiveUserControl<DataModelNodeCustomViewModel>
|
||||
{
|
||||
public DataModelNodeCustomView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +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:local="clr-namespace:Artemis.VisualScripting.Nodes.CustomViews"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
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>
|
||||
@@ -1,191 +1,151 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.ComponentModel;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Events;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Artemis.VisualScripting.Nodes.DataModel.CustomViewModels;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.DataModel
|
||||
namespace Artemis.VisualScripting.Nodes.DataModel;
|
||||
|
||||
[Node("Data Model-Event", "Responds to a data model event trigger", "Data Model", OutputType = typeof(bool))]
|
||||
public class DataModelEventNode : Node<DataModelPathEntity, DataModelEventNodeCustomViewModel>, IDisposable
|
||||
{
|
||||
[Node("Data Model-Event", "Responds to a data model event trigger", "Data Model", OutputType = typeof(bool))]
|
||||
public class DataModelEventNode : Node<DataModelPathEntity, DataModelEventNodeCustomViewModel>, IDisposable
|
||||
private int _currentIndex;
|
||||
private Type _currentType;
|
||||
private DataModelPath? _dataModelPath;
|
||||
private DateTime _lastTrigger;
|
||||
private bool _updating;
|
||||
|
||||
public DataModelEventNode() : base("Data Model-Event", "Responds to a data model event trigger")
|
||||
{
|
||||
private DataModelPath _dataModelPath;
|
||||
private DateTime _lastTrigger;
|
||||
private int _currentIndex;
|
||||
private Type _currentType;
|
||||
private bool _updating;
|
||||
_currentType = typeof(object);
|
||||
|
||||
public DataModelEventNode() : base("Data Model-Event", "Responds to a data model event trigger")
|
||||
{
|
||||
_currentType = typeof(object);
|
||||
CreateCycleValues(typeof(object), 1);
|
||||
Output = CreateOutputPin(typeof(object));
|
||||
}
|
||||
CycleValues = CreateInputPinCollection(typeof(object), "", 0);
|
||||
Output = CreateOutputPin(typeof(object));
|
||||
|
||||
private void CreateCycleValues(Type type, int initialCount)
|
||||
CycleValues.PinAdded += CycleValuesOnPinAdded;
|
||||
CycleValues.PinRemoved += CycleValuesOnPinRemoved;
|
||||
CycleValues.Add(CycleValues.CreatePin());
|
||||
|
||||
// Monitor storage for changes
|
||||
StorageModified += (_, _) => UpdateDataModelPath();
|
||||
}
|
||||
|
||||
public INodeScript? Script { get; set; }
|
||||
|
||||
public InputPinCollection CycleValues { get; }
|
||||
public OutputPin Output { get; }
|
||||
|
||||
public override void Initialize(INodeScript script)
|
||||
{
|
||||
Script = script;
|
||||
|
||||
if (Storage == null)
|
||||
return;
|
||||
|
||||
UpdateDataModelPath();
|
||||
}
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
object? outputValue = null;
|
||||
if (_dataModelPath?.GetValue() is IDataModelEvent dataModelEvent)
|
||||
{
|
||||
if (CycleValues != null)
|
||||
if (dataModelEvent.LastTrigger > _lastTrigger)
|
||||
{
|
||||
CycleValues.PinAdded -= CycleValuesOnPinAdded;
|
||||
CycleValues.PinRemoved -= CycleValuesOnPinRemoved;
|
||||
foreach (IPin pin in CycleValues)
|
||||
{
|
||||
pin.PinConnected -= OnPinConnected;
|
||||
pin.PinDisconnected -= OnPinDisconnected;
|
||||
}
|
||||
_lastTrigger = dataModelEvent.LastTrigger;
|
||||
_currentIndex++;
|
||||
|
||||
RemovePinCollection(CycleValues);
|
||||
if (_currentIndex >= CycleValues.Count())
|
||||
_currentIndex = 0;
|
||||
}
|
||||
|
||||
CycleValues = CreateInputPinCollection(type, "", initialCount);
|
||||
CycleValues.PinAdded += CycleValuesOnPinAdded;
|
||||
CycleValues.PinRemoved += CycleValuesOnPinRemoved;
|
||||
foreach (IPin pin in CycleValues)
|
||||
{
|
||||
pin.PinConnected += OnPinConnected;
|
||||
pin.PinDisconnected += OnPinDisconnected;
|
||||
}
|
||||
outputValue = CycleValues.ElementAt(_currentIndex).PinValue;
|
||||
}
|
||||
|
||||
private void CycleValuesOnPinAdded(object sender, SingleValueEventArgs<IPin> e)
|
||||
if (Output.Type.IsInstanceOfType(outputValue))
|
||||
Output.Value = outputValue;
|
||||
else if (Output.Type.IsValueType)
|
||||
Output.Value = Output.Type.GetDefault()!;
|
||||
}
|
||||
|
||||
private void CycleValuesOnPinAdded(object? sender, SingleValueEventArgs<IPin> e)
|
||||
{
|
||||
e.Value.PinConnected += OnPinConnected;
|
||||
e.Value.PinDisconnected += OnPinDisconnected;
|
||||
}
|
||||
|
||||
private void CycleValuesOnPinRemoved(object? sender, SingleValueEventArgs<IPin> e)
|
||||
{
|
||||
e.Value.PinConnected -= OnPinConnected;
|
||||
e.Value.PinDisconnected -= OnPinDisconnected;
|
||||
}
|
||||
|
||||
private void OnPinDisconnected(object? sender, SingleValueEventArgs<IPin> e)
|
||||
{
|
||||
ProcessPinDisconnected();
|
||||
}
|
||||
|
||||
private void OnPinConnected(object? sender, SingleValueEventArgs<IPin> e)
|
||||
{
|
||||
ProcessPinConnected(e.Value);
|
||||
}
|
||||
|
||||
private void ProcessPinConnected(IPin source)
|
||||
{
|
||||
if (_updating)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
e.Value.PinConnected += OnPinConnected;
|
||||
e.Value.PinDisconnected += OnPinDisconnected;
|
||||
}
|
||||
_updating = true;
|
||||
|
||||
private void CycleValuesOnPinRemoved(object sender, SingleValueEventArgs<IPin> e)
|
||||
{
|
||||
e.Value.PinConnected -= OnPinConnected;
|
||||
e.Value.PinDisconnected -= OnPinDisconnected;
|
||||
}
|
||||
|
||||
private void OnPinDisconnected(object sender, SingleValueEventArgs<IPin> e)
|
||||
{
|
||||
ProcessPinDisconnected();
|
||||
}
|
||||
|
||||
private void OnPinConnected(object sender, SingleValueEventArgs<IPin> e)
|
||||
{
|
||||
IPin source = e.Value;
|
||||
IPin target = (IPin) sender;
|
||||
ProcessPinConnected(source, target);
|
||||
}
|
||||
|
||||
public InputPinCollection CycleValues { get; set; }
|
||||
public OutputPin Output { get; set; }
|
||||
public INodeScript Script { get; set; }
|
||||
|
||||
public DataModelPath DataModelPath
|
||||
{
|
||||
get => _dataModelPath;
|
||||
set => SetAndNotify(ref _dataModelPath, value);
|
||||
}
|
||||
|
||||
public override void Initialize(INodeScript script)
|
||||
{
|
||||
Script = script;
|
||||
|
||||
if (Storage == null)
|
||||
return;
|
||||
|
||||
DataModelPath = new DataModelPath(Storage);
|
||||
}
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
object outputValue = null;
|
||||
if (DataModelPath?.GetValue() is IDataModelEvent dataModelEvent)
|
||||
{
|
||||
if (dataModelEvent.LastTrigger > _lastTrigger)
|
||||
{
|
||||
_lastTrigger = dataModelEvent.LastTrigger;
|
||||
_currentIndex++;
|
||||
|
||||
if (_currentIndex >= CycleValues.Count())
|
||||
_currentIndex = 0;
|
||||
}
|
||||
|
||||
outputValue = CycleValues.ElementAt(_currentIndex).PinValue;
|
||||
}
|
||||
|
||||
if (Output.Type.IsInstanceOfType(outputValue))
|
||||
Output.Value = outputValue;
|
||||
else if (Output.Type.IsValueType)
|
||||
Output.Value = Output.Type.GetDefault()!;
|
||||
}
|
||||
|
||||
private void ProcessPinConnected(IPin source, IPin target)
|
||||
{
|
||||
if (_updating)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
_updating = true;
|
||||
|
||||
// No need to change anything if the types haven't changed
|
||||
if (_currentType == source.Type)
|
||||
return;
|
||||
|
||||
int reconnectIndex = CycleValues.ToList().IndexOf(target);
|
||||
// No need to change anything if the types haven't changed
|
||||
if (_currentType != source.Type)
|
||||
ChangeCurrentType(source.Type);
|
||||
|
||||
if (reconnectIndex != -1)
|
||||
{
|
||||
CycleValues.ToList()[reconnectIndex].ConnectTo(source);
|
||||
source.ConnectTo(CycleValues.ToList()[reconnectIndex]);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_updating = false;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
_currentType = type;
|
||||
}
|
||||
|
||||
private void ProcessPinDisconnected()
|
||||
{
|
||||
if (_updating)
|
||||
return;
|
||||
try
|
||||
{
|
||||
// If there's still a connected pin, stick to the current type
|
||||
if (CycleValues.Any(v => v.ConnectedTo.Any()))
|
||||
return;
|
||||
|
||||
ChangeCurrentType(typeof(object));
|
||||
}
|
||||
finally
|
||||
{
|
||||
_updating = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePinsType(IPin source)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
finally
|
||||
{
|
||||
_updating = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void UpdateDataModelPath()
|
||||
{
|
||||
DataModelPath? old = _dataModelPath;
|
||||
_dataModelPath = Storage != null ? new DataModelPath(Storage) : null;
|
||||
old?.Dispose();
|
||||
}
|
||||
|
||||
private void ChangeCurrentType(Type type)
|
||||
{
|
||||
CycleValues.ChangeType(type);
|
||||
Output.ChangeType(type);
|
||||
|
||||
_currentType = type;
|
||||
}
|
||||
|
||||
private void ProcessPinDisconnected()
|
||||
{
|
||||
if (_updating)
|
||||
return;
|
||||
try
|
||||
{
|
||||
// If there's still a connected pin, stick to the current type
|
||||
if (CycleValues.Any(v => v.ConnectedTo.Any()))
|
||||
return;
|
||||
|
||||
ChangeCurrentType(typeof(object));
|
||||
}
|
||||
finally
|
||||
{
|
||||
_updating = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
_dataModelPath?.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,97 +1,82 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Artemis.Core;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Artemis.VisualScripting.Nodes.DataModel.CustomViewModels;
|
||||
using Stylet;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.DataModel
|
||||
namespace Artemis.VisualScripting.Nodes.DataModel;
|
||||
|
||||
[Node("Data Model-Value", "Outputs a selectable data model value.", "Data Model")]
|
||||
public class DataModelNode : Node<DataModelPathEntity, DataModelNodeCustomViewModel>, IDisposable
|
||||
{
|
||||
[Node("Data Model-Value", "Outputs a selectable data model value.", "Data Model")]
|
||||
public class DataModelNode : Node<DataModelPathEntity, DataModelNodeCustomViewModel>, IDisposable
|
||||
private DataModelPath? _dataModelPath;
|
||||
|
||||
public DataModelNode() : base("Data Model", "Outputs a selectable data model value")
|
||||
{
|
||||
private DataModelPath _dataModelPath;
|
||||
Output = CreateOutputPin(typeof(object));
|
||||
StorageModified += (_, _) => UpdateDataModelPath();
|
||||
}
|
||||
|
||||
public DataModelNode() : base("Data Model", "Outputs a selectable data model value")
|
||||
public INodeScript? Script { get; private set; }
|
||||
public OutputPin Output { get; }
|
||||
|
||||
public override void Initialize(INodeScript script)
|
||||
{
|
||||
Script = script;
|
||||
|
||||
if (Storage == null)
|
||||
return;
|
||||
|
||||
UpdateDataModelPath();
|
||||
}
|
||||
|
||||
private void UpdateDataModelPath()
|
||||
{
|
||||
DataModelPath? old = _dataModelPath;
|
||||
old?.Dispose();
|
||||
|
||||
_dataModelPath = Storage != null ? new DataModelPath(Storage) : null;
|
||||
if (_dataModelPath != null)
|
||||
_dataModelPath.PathValidated += DataModelPathOnPathValidated;
|
||||
UpdateOutputPin();
|
||||
}
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
if (_dataModelPath == null || !_dataModelPath.IsValid)
|
||||
return;
|
||||
|
||||
object? pathValue = _dataModelPath.GetValue();
|
||||
if (pathValue == null)
|
||||
{
|
||||
if (!Output.Type.IsValueType)
|
||||
Output.Value = null;
|
||||
}
|
||||
|
||||
public INodeScript Script { get; private set; }
|
||||
public OutputPin Output { get; private set; }
|
||||
|
||||
public DataModelPath DataModelPath
|
||||
else
|
||||
{
|
||||
get => _dataModelPath;
|
||||
set => SetAndNotify(ref _dataModelPath, value);
|
||||
}
|
||||
|
||||
public override void Initialize(INodeScript script)
|
||||
{
|
||||
Script = script;
|
||||
|
||||
if (Storage == null)
|
||||
return;
|
||||
|
||||
DataModelPath = new DataModelPath(Storage);
|
||||
DataModelPath.PathValidated += DataModelPathOnPathValidated;
|
||||
|
||||
UpdateOutputPin(false);
|
||||
}
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
if (Output != null)
|
||||
{
|
||||
RemovePin(Output);
|
||||
Output = null;
|
||||
}
|
||||
|
||||
if (type != null)
|
||||
Output = CreateOutputPin(type);
|
||||
|
||||
if (loadConnections && Script is NodeScript nodeScript)
|
||||
nodeScript.LoadConnections();
|
||||
}
|
||||
|
||||
private void DataModelPathOnPathValidated(object sender, EventArgs e)
|
||||
{
|
||||
Execute.OnUIThread(() => UpdateOutputPin(true));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
DataModelPath?.Dispose();
|
||||
Output.Value = Output.Type == typeof(Numeric) ? new Numeric(pathValue) : pathValue;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateOutputPin()
|
||||
{
|
||||
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 />
|
||||
public void Dispose()
|
||||
{
|
||||
_dataModelPath?.Dispose();
|
||||
}
|
||||
}
|
||||
+45
-49
@@ -1,58 +1,54 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Collections.ObjectModel;
|
||||
using Artemis.Core;
|
||||
using Artemis.VisualScripting.Nodes.CustomViewModels;
|
||||
using Stylet;
|
||||
using Artemis.UI.Shared.VisualScripting;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Easing.CustomViewModels
|
||||
namespace Artemis.VisualScripting.Nodes.Easing.CustomViewModels;
|
||||
|
||||
public class EasingTypeNodeCustomViewModel : CustomNodeViewModel
|
||||
{
|
||||
public class EasingTypeNodeCustomViewModel : CustomNodeViewModel
|
||||
private readonly EasingTypeNode _node;
|
||||
private NodeEasingViewModel _selectedEasingViewModel;
|
||||
|
||||
public EasingTypeNodeCustomViewModel(EasingTypeNode node, INodeScript script) : base(node, script)
|
||||
{
|
||||
private readonly EasingTypeNode _node;
|
||||
private NodeEasingViewModel _selectedEasingViewModel;
|
||||
_node = node;
|
||||
EasingViewModels = new ObservableCollection<NodeEasingViewModel>(Enum.GetValues(typeof(Easings.Functions)).Cast<Easings.Functions>().Select(e => new NodeEasingViewModel(e)));
|
||||
}
|
||||
|
||||
public EasingTypeNodeCustomViewModel(EasingTypeNode node) : base(node)
|
||||
public ObservableCollection<NodeEasingViewModel> EasingViewModels { get; }
|
||||
|
||||
public NodeEasingViewModel SelectedEasingViewModel
|
||||
{
|
||||
get => _selectedEasingViewModel;
|
||||
set
|
||||
{
|
||||
_node = node;
|
||||
EasingViewModels = new BindableCollection<NodeEasingViewModel>(Enum.GetValues(typeof(Easings.Functions)).Cast<Easings.Functions>().Select(e => new NodeEasingViewModel(e)));
|
||||
}
|
||||
|
||||
public BindableCollection<NodeEasingViewModel> EasingViewModels { get; }
|
||||
|
||||
public NodeEasingViewModel SelectedEasingViewModel
|
||||
{
|
||||
get => _selectedEasingViewModel;
|
||||
set
|
||||
{
|
||||
_selectedEasingViewModel = value;
|
||||
_node.Storage = _selectedEasingViewModel.EasingFunction;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnActivate()
|
||||
{
|
||||
_node.PropertyChanged += NodeOnPropertyChanged;
|
||||
SelectedEasingViewModel = GetNodeEasingViewModel();
|
||||
}
|
||||
|
||||
public override void OnDeactivate()
|
||||
{
|
||||
_node.PropertyChanged -= NodeOnPropertyChanged;
|
||||
}
|
||||
|
||||
private void NodeOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(_node.Storage))
|
||||
{
|
||||
_selectedEasingViewModel = GetNodeEasingViewModel();
|
||||
NotifyOfPropertyChange(nameof(SelectedEasingViewModel));
|
||||
}
|
||||
}
|
||||
|
||||
private NodeEasingViewModel GetNodeEasingViewModel()
|
||||
{
|
||||
return EasingViewModels.FirstOrDefault(vm => vm.EasingFunction == _node.Storage);
|
||||
_selectedEasingViewModel = value;
|
||||
_node.Storage = _selectedEasingViewModel.EasingFunction;
|
||||
}
|
||||
}
|
||||
|
||||
// public override void OnActivate()
|
||||
// {
|
||||
// _node.PropertyChanged += NodeOnPropertyChanged;
|
||||
// SelectedEasingViewModel = GetNodeEasingViewModel();
|
||||
// }
|
||||
//
|
||||
// public override void OnDeactivate()
|
||||
// {
|
||||
// _node.PropertyChanged -= NodeOnPropertyChanged;
|
||||
// }
|
||||
//
|
||||
// private void NodeOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
// {
|
||||
// if (e.PropertyName == nameof(_node.Storage))
|
||||
// {
|
||||
// _selectedEasingViewModel = GetNodeEasingViewModel();
|
||||
// NotifyOfPropertyChange(nameof(SelectedEasingViewModel));
|
||||
// }
|
||||
// }
|
||||
|
||||
private NodeEasingViewModel GetNodeEasingViewModel()
|
||||
{
|
||||
return EasingViewModels.FirstOrDefault(vm => vm.EasingFunction == _node.Storage);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,27 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared;
|
||||
using Avalonia;
|
||||
using Humanizer;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Easing.CustomViewModels
|
||||
namespace Artemis.VisualScripting.Nodes.Easing.CustomViewModels;
|
||||
|
||||
public class NodeEasingViewModel : ViewModelBase
|
||||
{
|
||||
public class NodeEasingViewModel : PropertyChangedBase
|
||||
public NodeEasingViewModel(Easings.Functions easingFunction)
|
||||
{
|
||||
public NodeEasingViewModel(Easings.Functions easingFunction)
|
||||
EasingFunction = easingFunction;
|
||||
Description = easingFunction.Humanize();
|
||||
|
||||
EasingPoints = new List<Point>();
|
||||
for (int i = 1; i <= 10; i++)
|
||||
{
|
||||
EasingFunction = easingFunction;
|
||||
Description = easingFunction.Humanize();
|
||||
|
||||
EasingPoints = new PointCollection();
|
||||
for (int i = 1; i <= 10; i++)
|
||||
{
|
||||
int x = i;
|
||||
double y = Easings.Interpolate(i / 10.0, EasingFunction) * 10;
|
||||
EasingPoints.Add(new Point(x, y));
|
||||
}
|
||||
int x = i;
|
||||
double y = Easings.Interpolate(i / 10.0, EasingFunction) * 10;
|
||||
EasingPoints.Add(new Point(x, y));
|
||||
}
|
||||
|
||||
public Easings.Functions EasingFunction { get; }
|
||||
public PointCollection EasingPoints { get; }
|
||||
public string Description { get; }
|
||||
}
|
||||
|
||||
public Easings.Functions EasingFunction { get; }
|
||||
public List<Point> EasingPoints { get; }
|
||||
public string Description { get; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.VisualScripting.Nodes.Easing.CustomViews.EasingTypeNodeCustomView">
|
||||
<controls:EnumComboBox Classes="condensed" MinWidth="75" Value="{Binding Node.Storage}"/>
|
||||
</UserControl>
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
using Artemis.VisualScripting.Nodes.Easing.CustomViewModels;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Easing.CustomViews
|
||||
{
|
||||
public partial class EasingTypeNodeCustomView : ReactiveUserControl<EasingTypeNodeCustomViewModel>
|
||||
{
|
||||
public EasingTypeNodeCustomView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
<UserControl x:Class="Artemis.VisualScripting.Nodes.Easing.CustomViews.EasingTypeNodeCustomView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.VisualScripting.Nodes.Easing.CustomViews"
|
||||
xmlns:viewModels="clr-namespace:Artemis.VisualScripting.Nodes.Easing.CustomViewModels"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<ComboBox VerticalAlignment="Center"
|
||||
HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding EasingViewModels}"
|
||||
SelectedItem="{Binding SelectedEasingViewModel}">
|
||||
<ComboBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ComboBox.ItemsPanel>
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type viewModels:NodeEasingViewModel}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Polyline Stroke="{DynamicResource MaterialDesignBody}"
|
||||
StrokeThickness="1.5"
|
||||
Points="{Binding EasingPoints}"
|
||||
Stretch="Uniform"
|
||||
Width="14"
|
||||
Height="14"
|
||||
Margin="0 0 10 0" />
|
||||
<TextBlock Text="{Binding Description}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
</UserControl>
|
||||
@@ -1,21 +1,20 @@
|
||||
using Artemis.Core;
|
||||
using Artemis.VisualScripting.Nodes.Easing.CustomViewModels;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Easing
|
||||
namespace Artemis.VisualScripting.Nodes.Easing;
|
||||
|
||||
[Node("Easing Type", "Outputs a selectable easing type.", "Easing", OutputType = typeof(Easings.Functions))]
|
||||
public class EasingTypeNode : Node<Easings.Functions, EasingTypeNodeCustomViewModel>
|
||||
{
|
||||
[Node("Easing Type", "Outputs a selectable easing type.", "Easing", OutputType = typeof(Easings.Functions))]
|
||||
public class EasingTypeNode : Node<Easings.Functions, EasingTypeNodeCustomViewModel>
|
||||
public EasingTypeNode() : base("Easing Type", "Outputs a selectable easing type.")
|
||||
{
|
||||
public EasingTypeNode() : base("Easing Type", "Outputs a selectable easing type.")
|
||||
{
|
||||
Output = CreateOutputPin<Easings.Functions>();
|
||||
}
|
||||
Output = CreateOutputPin<Easings.Functions>();
|
||||
}
|
||||
|
||||
public OutputPin<Easings.Functions> Output { get; }
|
||||
public OutputPin<Easings.Functions> Output { get; }
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Output.Value = Storage;
|
||||
}
|
||||
public override void Evaluate()
|
||||
{
|
||||
Output.Value = Storage;
|
||||
}
|
||||
}
|
||||
@@ -1,68 +1,66 @@
|
||||
using System;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Easing
|
||||
namespace Artemis.VisualScripting.Nodes.Easing;
|
||||
|
||||
[Node("Numeric Easing", "Outputs an eased numeric value", "Easing", InputType = typeof(Numeric), OutputType = typeof(Numeric))]
|
||||
public class NumericEasingNode : Node
|
||||
{
|
||||
[Node("Numeric Easing", "Outputs an eased numeric value", "Easing", InputType = typeof(Numeric), OutputType = typeof(Numeric))]
|
||||
public class NumericEasingNode : Node
|
||||
private float _currentValue;
|
||||
private DateTime _lastEvaluate = DateTime.MinValue;
|
||||
private float _progress;
|
||||
private float _sourceValue;
|
||||
private float _targetValue;
|
||||
|
||||
public NumericEasingNode() : base("Numeric Easing", "Outputs an eased numeric value")
|
||||
{
|
||||
private DateTime _lastEvaluate = DateTime.MinValue;
|
||||
private float _progress;
|
||||
private float _currentValue;
|
||||
private float _sourceValue;
|
||||
private float _targetValue;
|
||||
Input = CreateInputPin<Numeric>();
|
||||
EasingTime = CreateInputPin<Numeric>("delay");
|
||||
EasingFunction = CreateInputPin<Easings.Functions>("function");
|
||||
|
||||
public NumericEasingNode() : base("Numeric Easing", "Outputs an eased numeric value")
|
||||
Output = CreateOutputPin<Numeric>();
|
||||
}
|
||||
|
||||
public InputPin<Numeric> Input { get; set; }
|
||||
public InputPin<Numeric> EasingTime { get; set; }
|
||||
public InputPin<Easings.Functions> EasingFunction { get; set; }
|
||||
|
||||
public OutputPin<Numeric> Output { get; set; }
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
// If the value changed reset progress
|
||||
if (Math.Abs(_targetValue - Input.Value) > 0.001f)
|
||||
{
|
||||
Input = CreateInputPin<Numeric>();
|
||||
EasingTime = CreateInputPin<Numeric>("delay");
|
||||
EasingFunction = CreateInputPin<Easings.Functions>("function");
|
||||
|
||||
Output = CreateOutputPin<Numeric>();
|
||||
_sourceValue = _currentValue;
|
||||
_targetValue = Input.Value;
|
||||
_progress = 0f;
|
||||
}
|
||||
|
||||
public InputPin<Numeric> Input { get; set; }
|
||||
public InputPin<Numeric> EasingTime { get; set; }
|
||||
public InputPin<Easings.Functions> EasingFunction { get; set; }
|
||||
|
||||
public OutputPin<Numeric> Output { get; set; }
|
||||
|
||||
public override void Evaluate()
|
||||
// Update until finished
|
||||
if (_progress < 1f)
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
// If the value changed reset progress
|
||||
if (Math.Abs(_targetValue - Input.Value) > 0.001f)
|
||||
{
|
||||
_sourceValue = _currentValue;
|
||||
_targetValue = Input.Value;
|
||||
_progress = 0f;
|
||||
}
|
||||
|
||||
// Update until finished
|
||||
if (_progress < 1f)
|
||||
{
|
||||
Update();
|
||||
Output.Value = new Numeric(_currentValue);
|
||||
}
|
||||
// Stop updating past 1 and use the target value
|
||||
else
|
||||
{
|
||||
Output.Value = new Numeric(_targetValue);
|
||||
}
|
||||
|
||||
_lastEvaluate = now;
|
||||
Update();
|
||||
Output.Value = new Numeric(_currentValue);
|
||||
}
|
||||
// Stop updating past 1 and use the target value
|
||||
else
|
||||
{
|
||||
Output.Value = new Numeric(_targetValue);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
TimeSpan delta = DateTime.Now - _lastEvaluate;
|
||||
_lastEvaluate = now;
|
||||
}
|
||||
|
||||
// In case of odd delta's, keep progress between 0f and 1f
|
||||
_progress = Math.Clamp(_progress + (float) delta.TotalMilliseconds / EasingTime.Value, 0f, 1f);
|
||||
private void Update()
|
||||
{
|
||||
TimeSpan delta = DateTime.Now - _lastEvaluate;
|
||||
|
||||
double eased = _sourceValue + (_targetValue - _sourceValue) * Easings.Interpolate(_progress, EasingFunction.Value);
|
||||
_currentValue = (float) eased;
|
||||
}
|
||||
// In case of odd delta's, keep progress between 0f and 1f
|
||||
_progress = Math.Clamp(_progress + (float) delta.TotalMilliseconds / EasingTime.Value, 0f, 1f);
|
||||
|
||||
double eased = _sourceValue + (_targetValue - _sourceValue) * Easings.Interpolate(_progress, EasingFunction.Value);
|
||||
_currentValue = (float) eased;
|
||||
}
|
||||
}
|
||||
@@ -1,67 +1,65 @@
|
||||
using System;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Easing
|
||||
namespace Artemis.VisualScripting.Nodes.Easing;
|
||||
|
||||
[Node("Color Easing", "Outputs an eased color value", "Easing", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||
public class SKColorEasingNode : Node
|
||||
{
|
||||
[Node("Color Easing", "Outputs an eased color value", "Easing", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||
public class SKColorEasingNode : Node
|
||||
private SKColor _currentValue;
|
||||
private DateTime _lastEvaluate = DateTime.MinValue;
|
||||
private float _progress;
|
||||
private SKColor _sourceValue;
|
||||
private SKColor _targetValue;
|
||||
|
||||
public SKColorEasingNode() : base("Color Easing", "Outputs an eased color value")
|
||||
{
|
||||
private DateTime _lastEvaluate = DateTime.MinValue;
|
||||
private float _progress;
|
||||
private SKColor _currentValue;
|
||||
private SKColor _sourceValue;
|
||||
private SKColor _targetValue;
|
||||
Input = CreateInputPin<SKColor>();
|
||||
EasingTime = CreateInputPin<Numeric>("delay");
|
||||
EasingFunction = CreateInputPin<Easings.Functions>("function");
|
||||
|
||||
public SKColorEasingNode() : base("Color Easing", "Outputs an eased color value")
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
}
|
||||
|
||||
public InputPin<SKColor> Input { get; set; }
|
||||
public InputPin<Numeric> EasingTime { get; set; }
|
||||
public InputPin<Easings.Functions> EasingFunction { get; set; }
|
||||
|
||||
public OutputPin<SKColor> Output { get; set; }
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
// If the value changed reset progress
|
||||
if (_targetValue != Input.Value)
|
||||
{
|
||||
Input = CreateInputPin<SKColor>();
|
||||
EasingTime = CreateInputPin<Numeric>("delay");
|
||||
EasingFunction = CreateInputPin<Easings.Functions>("function");
|
||||
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
_sourceValue = _currentValue;
|
||||
_targetValue = Input.Value;
|
||||
_progress = 0f;
|
||||
}
|
||||
|
||||
public InputPin<SKColor> Input { get; set; }
|
||||
public InputPin<Numeric> EasingTime { get; set; }
|
||||
public InputPin<Easings.Functions> EasingFunction { get; set; }
|
||||
|
||||
public OutputPin<SKColor> Output { get; set; }
|
||||
|
||||
public override void Evaluate()
|
||||
// Update until finished
|
||||
if (_progress < 1f)
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
// If the value changed reset progress
|
||||
if (_targetValue != Input.Value)
|
||||
{
|
||||
_sourceValue = _currentValue;
|
||||
_targetValue = Input.Value;
|
||||
_progress = 0f;
|
||||
}
|
||||
|
||||
// Update until finished
|
||||
if (_progress < 1f)
|
||||
{
|
||||
Update();
|
||||
Output.Value = _currentValue;
|
||||
}
|
||||
// Stop updating past 1 and use the target value
|
||||
else
|
||||
{
|
||||
Output.Value = _targetValue;
|
||||
}
|
||||
|
||||
_lastEvaluate = now;
|
||||
Update();
|
||||
Output.Value = _currentValue;
|
||||
}
|
||||
// Stop updating past 1 and use the target value
|
||||
else
|
||||
{
|
||||
Output.Value = _targetValue;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
TimeSpan delta = DateTime.Now - _lastEvaluate;
|
||||
_lastEvaluate = now;
|
||||
}
|
||||
|
||||
// In case of odd delta's, keep progress between 0f and 1f
|
||||
_progress = Math.Clamp(_progress + (float) delta.TotalMilliseconds / EasingTime.Value, 0f, 1f);
|
||||
_currentValue = _sourceValue.Interpolate(_targetValue, (float) Easings.Interpolate(_progress, EasingFunction.Value));
|
||||
}
|
||||
private void Update()
|
||||
{
|
||||
TimeSpan delta = DateTime.Now - _lastEvaluate;
|
||||
|
||||
// In case of odd delta's, keep progress between 0f and 1f
|
||||
_progress = Math.Clamp(_progress + (float) delta.TotalMilliseconds / EasingTime.Value, 0f, 1f);
|
||||
_currentValue = _sourceValue.Interpolate(_targetValue, (float) Easings.Interpolate(_progress, EasingFunction.Value));
|
||||
}
|
||||
}
|
||||
@@ -1,128 +1,124 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core;
|
||||
using Artemis.VisualScripting.Nodes.CustomViewModels;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes
|
||||
namespace Artemis.VisualScripting.Nodes;
|
||||
|
||||
[Node("Layer/Folder Property", "Outputs the property of a selected layer or folder", "External")]
|
||||
public class LayerPropertyNode : Node<LayerPropertyNodeEntity, LayerPropertyNodeCustomViewModel>
|
||||
{
|
||||
[Node("Layer/Folder Property", "Outputs the property of a selected layer or folder", "External")]
|
||||
public class LayerPropertyNode : Node<LayerPropertyNodeEntity, LayerPropertyNodeCustomViewModel>
|
||||
private readonly object _layerPropertyLock = new();
|
||||
|
||||
public INodeScript Script { get; private set; }
|
||||
public RenderProfileElement ProfileElement { get; private set; }
|
||||
public ILayerProperty LayerProperty { get; private set; }
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
private readonly object _layerPropertyLock = new();
|
||||
|
||||
public INodeScript Script { get; private set; }
|
||||
public RenderProfileElement ProfileElement { get; private set; }
|
||||
public ILayerProperty LayerProperty { get; private set; }
|
||||
|
||||
public override void Evaluate()
|
||||
lock (_layerPropertyLock)
|
||||
{
|
||||
lock (_layerPropertyLock)
|
||||
{
|
||||
// In this case remove the pins so no further evaluations occur
|
||||
if (LayerProperty == null)
|
||||
{
|
||||
CreatePins();
|
||||
return;
|
||||
}
|
||||
|
||||
List<IDataBindingProperty> list = LayerProperty.BaseDataBinding.Properties.ToList();
|
||||
int index = 0;
|
||||
foreach (IPin pin in Pins)
|
||||
{
|
||||
OutputPin outputPin = (OutputPin) pin;
|
||||
IDataBindingProperty dataBindingProperty = list[index];
|
||||
index++;
|
||||
|
||||
// TODO: Is this really non-nullable?
|
||||
outputPin.Value = dataBindingProperty.GetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Initialize(INodeScript script)
|
||||
{
|
||||
Script = script;
|
||||
|
||||
if (script.Context is Profile profile)
|
||||
profile.ChildRemoved += ProfileOnChildRemoved;
|
||||
|
||||
LoadLayerProperty();
|
||||
}
|
||||
|
||||
public void LoadLayerProperty()
|
||||
{
|
||||
lock (_layerPropertyLock)
|
||||
{
|
||||
if (Script.Context is not Profile profile || Storage == null)
|
||||
return;
|
||||
|
||||
RenderProfileElement element = profile.GetAllRenderElements().FirstOrDefault(l => l.EntityId == Storage.ElementId);
|
||||
|
||||
ProfileElement = element;
|
||||
LayerProperty = element?.GetAllLayerProperties().FirstOrDefault(p => p.Path == Storage.PropertyPath);
|
||||
CreatePins();
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeProfileElement(RenderProfileElement profileElement)
|
||||
{
|
||||
lock (_layerPropertyLock)
|
||||
{
|
||||
ProfileElement = profileElement;
|
||||
LayerProperty = null;
|
||||
|
||||
Storage = new LayerPropertyNodeEntity
|
||||
{
|
||||
ElementId = ProfileElement?.EntityId ?? Guid.Empty,
|
||||
PropertyPath = null
|
||||
};
|
||||
|
||||
CreatePins();
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeLayerProperty(ILayerProperty layerProperty)
|
||||
{
|
||||
lock (_layerPropertyLock)
|
||||
{
|
||||
LayerProperty = layerProperty;
|
||||
|
||||
Storage = new LayerPropertyNodeEntity
|
||||
{
|
||||
ElementId = ProfileElement?.EntityId ?? Guid.Empty,
|
||||
PropertyPath = LayerProperty?.Path
|
||||
};
|
||||
|
||||
CreatePins();
|
||||
}
|
||||
}
|
||||
|
||||
private void CreatePins()
|
||||
{
|
||||
while (Pins.Any())
|
||||
RemovePin((Pin) Pins.First());
|
||||
|
||||
// In this case remove the pins so no further evaluations occur
|
||||
if (LayerProperty == null)
|
||||
{
|
||||
CreatePins();
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (IDataBindingProperty dataBindingRegistration in LayerProperty.BaseDataBinding.Properties)
|
||||
CreateOutputPin(dataBindingRegistration.ValueType, dataBindingRegistration.DisplayName);
|
||||
}
|
||||
List<IDataBindingProperty> list = LayerProperty.BaseDataBinding.Properties.ToList();
|
||||
int index = 0;
|
||||
foreach (IPin pin in Pins)
|
||||
{
|
||||
OutputPin outputPin = (OutputPin) pin;
|
||||
IDataBindingProperty dataBindingProperty = list[index];
|
||||
index++;
|
||||
|
||||
private void ProfileOnChildRemoved(object sender, EventArgs e)
|
||||
{
|
||||
if (Script.Context is not Profile profile)
|
||||
return;
|
||||
|
||||
if (!profile.GetAllRenderElements().Contains(ProfileElement))
|
||||
ChangeProfileElement(null);
|
||||
// TODO: Is this really non-nullable?
|
||||
outputPin.Value = dataBindingProperty.GetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LayerPropertyNodeEntity
|
||||
public override void Initialize(INodeScript script)
|
||||
{
|
||||
public Guid ElementId { get; set; }
|
||||
public string PropertyPath { get; set; }
|
||||
Script = script;
|
||||
|
||||
if (script.Context is Profile profile)
|
||||
profile.ChildRemoved += ProfileOnChildRemoved;
|
||||
|
||||
LoadLayerProperty();
|
||||
}
|
||||
|
||||
public void LoadLayerProperty()
|
||||
{
|
||||
lock (_layerPropertyLock)
|
||||
{
|
||||
if (Script.Context is not Profile profile || Storage == null)
|
||||
return;
|
||||
|
||||
RenderProfileElement element = profile.GetAllRenderElements().FirstOrDefault(l => l.EntityId == Storage.ElementId);
|
||||
|
||||
ProfileElement = element;
|
||||
LayerProperty = element?.GetAllLayerProperties().FirstOrDefault(p => p.Path == Storage.PropertyPath);
|
||||
CreatePins();
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeProfileElement(RenderProfileElement profileElement)
|
||||
{
|
||||
lock (_layerPropertyLock)
|
||||
{
|
||||
ProfileElement = profileElement;
|
||||
LayerProperty = null;
|
||||
|
||||
Storage = new LayerPropertyNodeEntity
|
||||
{
|
||||
ElementId = ProfileElement?.EntityId ?? Guid.Empty,
|
||||
PropertyPath = null
|
||||
};
|
||||
|
||||
CreatePins();
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeLayerProperty(ILayerProperty layerProperty)
|
||||
{
|
||||
lock (_layerPropertyLock)
|
||||
{
|
||||
LayerProperty = layerProperty;
|
||||
|
||||
Storage = new LayerPropertyNodeEntity
|
||||
{
|
||||
ElementId = ProfileElement?.EntityId ?? Guid.Empty,
|
||||
PropertyPath = LayerProperty?.Path
|
||||
};
|
||||
|
||||
CreatePins();
|
||||
}
|
||||
}
|
||||
|
||||
private void CreatePins()
|
||||
{
|
||||
while (Pins.Any())
|
||||
RemovePin((Pin) Pins.First());
|
||||
|
||||
if (LayerProperty == null)
|
||||
return;
|
||||
|
||||
foreach (IDataBindingProperty dataBindingRegistration in LayerProperty.BaseDataBinding.Properties)
|
||||
CreateOutputPin(dataBindingRegistration.ValueType, dataBindingRegistration.DisplayName);
|
||||
}
|
||||
|
||||
private void ProfileOnChildRemoved(object sender, EventArgs e)
|
||||
{
|
||||
if (Script.Context is not Profile profile)
|
||||
return;
|
||||
|
||||
if (!profile.GetAllRenderElements().Contains(ProfileElement))
|
||||
ChangeProfileElement(null);
|
||||
}
|
||||
}
|
||||
|
||||
public class LayerPropertyNodeEntity
|
||||
{
|
||||
public Guid ElementId { get; set; }
|
||||
public string PropertyPath { get; set; }
|
||||
}
|
||||
+5
-6
@@ -1,12 +1,11 @@
|
||||
using Artemis.Core;
|
||||
using Artemis.VisualScripting.Nodes.CustomViewModels;
|
||||
using Artemis.UI.Shared.VisualScripting;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Maths.CustomViewModels
|
||||
namespace Artemis.VisualScripting.Nodes.Maths.CustomViewModels;
|
||||
|
||||
public class MathExpressionNodeCustomViewModel : CustomNodeViewModel
|
||||
{
|
||||
public class MathExpressionNodeCustomViewModel : CustomNodeViewModel
|
||||
public MathExpressionNodeCustomViewModel(INode node, INodeScript script) : base(node, script)
|
||||
{
|
||||
public MathExpressionNodeCustomViewModel(INode node) : base(node)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-5
@@ -1,12 +1,11 @@
|
||||
<UserControl x:Class="Artemis.VisualScripting.Nodes.Maths.CustomViews.MathExpressionNodeCustomView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.VisualScripting.Nodes.Maths.CustomViews"
|
||||
mc:Ignorable="d"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<TextBox VerticalAlignment="Bottom"
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding Node.Storage}" />
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
@@ -1,119 +1,116 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core;
|
||||
using Artemis.VisualScripting.Nodes.Maths.CustomViewModels;
|
||||
using NoStringEvaluating.Contract;
|
||||
using NoStringEvaluating.Contract.Variables;
|
||||
using NoStringEvaluating.Models.Values;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Maths
|
||||
namespace Artemis.VisualScripting.Nodes.Maths;
|
||||
|
||||
[Node("Math Expression", "Outputs the result of a math expression.", "Mathematics", InputType = typeof(Numeric), OutputType = typeof(Numeric))]
|
||||
public class MathExpressionNode : Node<string, MathExpressionNodeCustomViewModel>
|
||||
{
|
||||
[Node("Math Expression", "Outputs the result of a math expression.", "Mathematics", InputType = typeof(Numeric), OutputType = typeof(Numeric))]
|
||||
public class MathExpressionNode : Node<string, MathExpressionNodeCustomViewModel>
|
||||
private readonly INoStringEvaluator _evaluator;
|
||||
private readonly PinsVariablesContainer _variables;
|
||||
|
||||
#region Constructors
|
||||
|
||||
public MathExpressionNode(INoStringEvaluator evaluator)
|
||||
: base("Math Expression", "Outputs the result of a math expression.")
|
||||
{
|
||||
private readonly INoStringEvaluator _evaluator;
|
||||
private readonly PinsVariablesContainer _variables;
|
||||
_evaluator = evaluator;
|
||||
Output = CreateOutputPin<Numeric>();
|
||||
Values = CreateInputPinCollection<Numeric>("Values", 2);
|
||||
Values.PinAdded += (_, _) => SetPinNames();
|
||||
Values.PinRemoved += (_, _) => SetPinNames();
|
||||
_variables = new PinsVariablesContainer(Values);
|
||||
|
||||
#region Constructors
|
||||
|
||||
public MathExpressionNode(INoStringEvaluator evaluator)
|
||||
: base("Math Expression", "Outputs the result of a math expression.")
|
||||
{
|
||||
_evaluator = evaluator;
|
||||
Output = CreateOutputPin<Numeric>();
|
||||
Values = CreateInputPinCollection<Numeric>("Values", 2);
|
||||
Values.PinAdded += (_, _) => SetPinNames();
|
||||
Values.PinRemoved += (_, _) => SetPinNames();
|
||||
_variables = new PinsVariablesContainer(Values);
|
||||
|
||||
SetPinNames();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public OutputPin<Numeric> Output { get; }
|
||||
public InputPinCollection<Numeric> Values { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
if (Storage != null)
|
||||
Output.Value = new Numeric(_evaluator.CalcNumber(Storage, _variables));
|
||||
}
|
||||
|
||||
private void SetPinNames()
|
||||
{
|
||||
int index = 1;
|
||||
foreach (IPin value in Values)
|
||||
{
|
||||
value.Name = ExcelColumnFromNumber(index).ToLower();
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ExcelColumnFromNumber(int column)
|
||||
{
|
||||
string columnString = "";
|
||||
decimal columnNumber = column;
|
||||
while (columnNumber > 0)
|
||||
{
|
||||
decimal currentLetterNumber = (columnNumber - 1) % 26;
|
||||
char currentLetter = (char) (currentLetterNumber + 65);
|
||||
columnString = currentLetter + columnString;
|
||||
columnNumber = (columnNumber - (currentLetterNumber + 1)) / 26;
|
||||
}
|
||||
|
||||
return columnString;
|
||||
}
|
||||
|
||||
#endregion
|
||||
SetPinNames();
|
||||
}
|
||||
|
||||
public class PinsVariablesContainer : IVariablesContainer
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public OutputPin<Numeric> Output { get; }
|
||||
public InputPinCollection<Numeric> Values { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
private readonly InputPinCollection<Numeric> _values;
|
||||
|
||||
public PinsVariablesContainer(InputPinCollection<Numeric> values)
|
||||
{
|
||||
_values = values;
|
||||
}
|
||||
|
||||
#region Implementation of IVariablesContainer
|
||||
|
||||
/// <inheritdoc />
|
||||
public IVariable AddOrUpdate(string name, double value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public EvaluatorValue GetValue(string name)
|
||||
{
|
||||
IPin pin = _values.FirstOrDefault(v => v.Name == name);
|
||||
if (pin?.PinValue is Numeric numeric)
|
||||
return new EvaluatorValue(numeric);
|
||||
return new EvaluatorValue(0);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TryGetValue(string name, out EvaluatorValue value)
|
||||
{
|
||||
IPin pin = _values.FirstOrDefault(v => v.Name == name);
|
||||
if (pin?.PinValue is Numeric numeric)
|
||||
{
|
||||
value = new EvaluatorValue(numeric);
|
||||
return true;
|
||||
}
|
||||
|
||||
value = new EvaluatorValue(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
if (Storage != null)
|
||||
Output.Value = new Numeric(_evaluator.CalcNumber(Storage, _variables));
|
||||
}
|
||||
|
||||
private void SetPinNames()
|
||||
{
|
||||
int index = 1;
|
||||
foreach (IPin value in Values)
|
||||
{
|
||||
value.Name = ExcelColumnFromNumber(index).ToLower();
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ExcelColumnFromNumber(int column)
|
||||
{
|
||||
string columnString = "";
|
||||
decimal columnNumber = column;
|
||||
while (columnNumber > 0)
|
||||
{
|
||||
decimal currentLetterNumber = (columnNumber - 1) % 26;
|
||||
char currentLetter = (char) (currentLetterNumber + 65);
|
||||
columnString = currentLetter + columnString;
|
||||
columnNumber = (columnNumber - (currentLetterNumber + 1)) / 26;
|
||||
}
|
||||
|
||||
return columnString;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class PinsVariablesContainer : IVariablesContainer
|
||||
{
|
||||
private readonly InputPinCollection<Numeric> _values;
|
||||
|
||||
public PinsVariablesContainer(InputPinCollection<Numeric> values)
|
||||
{
|
||||
_values = values;
|
||||
}
|
||||
|
||||
#region Implementation of IVariablesContainer
|
||||
|
||||
/// <inheritdoc />
|
||||
public IVariable AddOrUpdate(string name, double value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public EvaluatorValue GetValue(string name)
|
||||
{
|
||||
IPin pin = _values.FirstOrDefault(v => v.Name == name);
|
||||
if (pin?.PinValue is Numeric numeric)
|
||||
return new EvaluatorValue(numeric);
|
||||
return new EvaluatorValue(0);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TryGetValue(string name, out EvaluatorValue value)
|
||||
{
|
||||
IPin pin = _values.FirstOrDefault(v => v.Name == name);
|
||||
if (pin?.PinValue is Numeric numeric)
|
||||
{
|
||||
value = new EvaluatorValue(numeric);
|
||||
return true;
|
||||
}
|
||||
|
||||
value = new EvaluatorValue(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,28 +1,26 @@
|
||||
using System;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes.Maths
|
||||
namespace Artemis.VisualScripting.Nodes.Maths;
|
||||
|
||||
[Node("Round", "Outputs a rounded numeric value.", "Mathematics", InputType = typeof(Numeric), OutputType = typeof(Numeric))]
|
||||
public class RoundNode : Node
|
||||
{
|
||||
[Node("Round", "Outputs a rounded numeric value.", "Mathematics", InputType = typeof(Numeric), OutputType = typeof(Numeric))]
|
||||
public class RoundNode : Node
|
||||
public RoundNode() : base("Round", "Outputs a rounded numeric value.")
|
||||
{
|
||||
public RoundNode() : base("Round", "Outputs a rounded numeric value.")
|
||||
{
|
||||
Input = CreateInputPin<Numeric>();
|
||||
Output = CreateOutputPin<Numeric>();
|
||||
}
|
||||
|
||||
public OutputPin<Numeric> Output { get; set; }
|
||||
public InputPin<Numeric> Input { get; set; }
|
||||
|
||||
#region Overrides of Node
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Evaluate()
|
||||
{
|
||||
Output.Value = new Numeric(MathF.Round(Input.Value, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
#endregion
|
||||
Input = CreateInputPin<Numeric>();
|
||||
Output = CreateOutputPin<Numeric>();
|
||||
}
|
||||
|
||||
public OutputPin<Numeric> Output { get; set; }
|
||||
public InputPin<Numeric> Input { get; set; }
|
||||
|
||||
#region Overrides of Node
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Evaluate()
|
||||
{
|
||||
Output.Value = new Numeric(MathF.Round(Input.Value, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,63 +1,62 @@
|
||||
using Artemis.Core;
|
||||
using Artemis.VisualScripting.Nodes.CustomViewModels;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes
|
||||
namespace Artemis.VisualScripting.Nodes;
|
||||
|
||||
[Node("Numeric-Value", "Outputs a configurable static numeric value.", "Static", OutputType = typeof(Numeric))]
|
||||
public class StaticNumericValueNode : Node<Numeric, StaticNumericValueNodeCustomViewModel>
|
||||
{
|
||||
[Node("Numeric-Value", "Outputs a configurable static numeric value.", "Static", OutputType = typeof(Numeric))]
|
||||
public class StaticNumericValueNode : Node<Numeric, StaticNumericValueNodeCustomViewModel>
|
||||
#region Constructors
|
||||
|
||||
public StaticNumericValueNode()
|
||||
: base("Numeric", "Outputs a configurable numeric value.")
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public OutputPin<Numeric> Output { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public StaticNumericValueNode()
|
||||
: base("Numeric", "Outputs a configurable numeric value.")
|
||||
{
|
||||
Output = CreateOutputPin<Numeric>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Output.Value = Storage;
|
||||
}
|
||||
|
||||
#endregion
|
||||
Output = CreateOutputPin<Numeric>();
|
||||
}
|
||||
|
||||
[Node("String-Value", "Outputs a configurable static string value.", "Static", OutputType = typeof(string))]
|
||||
public class StaticStringValueNode : Node<string, StaticStringValueNodeCustomViewModel>
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public OutputPin<Numeric> Output { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public OutputPin<string> Output { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public StaticStringValueNode()
|
||||
: base("String", "Outputs a configurable string value.")
|
||||
{
|
||||
Output = CreateOutputPin<string>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Output.Value = Storage;
|
||||
}
|
||||
|
||||
#endregion
|
||||
Output.Value = Storage;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Node("String-Value", "Outputs a configurable static string value.", "Static", OutputType = typeof(string))]
|
||||
public class StaticStringValueNode : Node<string, StaticStringValueNodeCustomViewModel>
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public StaticStringValueNode()
|
||||
: base("String", "Outputs a configurable string value.")
|
||||
{
|
||||
Output = CreateOutputPin<string>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public OutputPin<string> Output { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Output.Value = Storage;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,39 +1,37 @@
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes
|
||||
namespace Artemis.VisualScripting.Nodes;
|
||||
|
||||
[Node("Format", "Formats the input string.", "Text", InputType = typeof(object), OutputType = typeof(string))]
|
||||
public class StringFormatNode : Node
|
||||
{
|
||||
[Node("Format", "Formats the input string.", "Text", InputType = typeof(object), OutputType = typeof(string))]
|
||||
public class StringFormatNode : Node
|
||||
#region Constructors
|
||||
|
||||
public StringFormatNode()
|
||||
: base("Format", "Formats the input string.")
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPin<string> Format { get; }
|
||||
public InputPinCollection<object> Values { get; }
|
||||
|
||||
public OutputPin<string> Output { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public StringFormatNode()
|
||||
: base("Format", "Formats the input string.")
|
||||
{
|
||||
Format = CreateInputPin<string>("Format");
|
||||
Values = CreateInputPinCollection<object>("Values", 1);
|
||||
Output = CreateOutputPin<string>("Result");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Output.Value = string.Format(Format.Value ?? string.Empty, Values.Values.ToArray());
|
||||
}
|
||||
|
||||
#endregion
|
||||
Format = CreateInputPin<string>("Format");
|
||||
Values = CreateInputPinCollection<object>("Values");
|
||||
Output = CreateOutputPin<string>("Result");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Output.Value = string.Format(Format.Value ?? string.Empty, Values.Values.ToArray());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPin<string> Format { get; }
|
||||
public InputPinCollection<object> Values { get; }
|
||||
|
||||
public OutputPin<string> Output { get; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,36 +1,35 @@
|
||||
using Artemis.Core;
|
||||
|
||||
namespace Artemis.VisualScripting.Nodes
|
||||
namespace Artemis.VisualScripting.Nodes;
|
||||
|
||||
[Node("Sum", "Sums the connected numeric values.", "Mathematics", InputType = typeof(Numeric), OutputType = typeof(Numeric))]
|
||||
public class SumNumericsNode : Node
|
||||
{
|
||||
[Node("Sum", "Sums the connected numeric values.", "Mathematics", InputType = typeof(Numeric), OutputType = typeof(Numeric))]
|
||||
public class SumNumericsNode : Node
|
||||
#region Constructors
|
||||
|
||||
public SumNumericsNode()
|
||||
: base("Sum", "Sums the connected numeric values.")
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public SumNumericsNode()
|
||||
: base("Sum", "Sums the connected numeric values.")
|
||||
{
|
||||
Values = CreateInputPinCollection<Numeric>("Values", 2);
|
||||
Sum = CreateOutputPin<Numeric>("Sum");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Sum.Value = Values.Values.Sum();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPinCollection<Numeric> Values { get; }
|
||||
|
||||
public OutputPin<Numeric> Sum { get; }
|
||||
|
||||
#endregion
|
||||
Values = CreateInputPinCollection<Numeric>("Values", 2);
|
||||
Sum = CreateOutputPin<Numeric>("Sum");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Evaluate()
|
||||
{
|
||||
Sum.Value = Values.Values.Sum();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public InputPinCollection<Numeric> Values { get; }
|
||||
|
||||
public OutputPin<Numeric> Sum { get; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.Teal.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Teal.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
@@ -1,108 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:dataModel="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared">
|
||||
<Style x:Key="DataModelConditionButton" TargetType="{x:Type Button}" BasedOn="{StaticResource MaterialDesignFlatAccentBgButton}">
|
||||
<Setter Property="Margin" Value="3 0" />
|
||||
<Setter Property="Padding" Value="6 4" />
|
||||
<Setter Property="Height" Value="22" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource PrimaryHueMidForegroundBrush}" />
|
||||
<Setter Property="FontSize" Value="12" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="DataModelConditionButtonLeftClickMenu" TargetType="{x:Type Button}" BasedOn="{StaticResource DataModelConditionButton}">
|
||||
<Style.Triggers>
|
||||
<EventTrigger RoutedEvent="Click">
|
||||
<EventTrigger.Actions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
|
||||
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True" />
|
||||
</BooleanAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger.Actions>
|
||||
</EventTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<ControlTemplate x:Key="DataModelSelectionTemplate">
|
||||
<StackPanel>
|
||||
<StackPanel.Resources>
|
||||
<DataTemplate DataType="{x:Type dataModel:DataModelPropertiesViewModel}">
|
||||
<TextBlock Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" ToolTipService.ShowOnDisabled="True"/>
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="{x:Type dataModel:DataModelListViewModel}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="FormatListBulleted" VerticalAlignment="Center" Margin="0 0 5 0" />
|
||||
<TextBlock Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" ToolTipService.ShowOnDisabled="True" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="{x:Type dataModel:DataModelEventViewModel}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="LightningBolt" VerticalAlignment="Center" Margin="0 0 5 0" />
|
||||
<TextBlock Text="{Binding PropertyDescription.Name}" ToolTip="Trigger layer on event" ToolTipService.ShowOnDisabled="True" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="{x:Type dataModel:DataModelPropertyViewModel}">
|
||||
<Grid>
|
||||
<!-- Value description -->
|
||||
<TextBlock Grid.Column="0" Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</StackPanel.Resources>
|
||||
<ContentPresenter Content="{Binding}" />
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
|
||||
<ControlTemplate x:Key="DataModelSelectionTemplateWithValues">
|
||||
<StackPanel>
|
||||
<StackPanel.Resources>
|
||||
<DataTemplate DataType="{x:Type dataModel:DataModelPropertiesViewModel}">
|
||||
<Grid ToolTip="{Binding PropertyDescription.Description}" ToolTipService.ShowOnDisabled="True">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Value description -->
|
||||
<TextBlock Grid.Column="0" Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" ToolTipService.ShowOnDisabled="True"/>
|
||||
|
||||
<!-- Value display -->
|
||||
<TextBlock Grid.Column="1" Text="{Binding DisplayValue}" HorizontalAlignment="Right" FontFamily="Consolas" Margin="15 0.5 0 0"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="{x:Type dataModel:DataModelListViewModel}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="FormatListBulleted" VerticalAlignment="Center" Margin="0 0 5 0" />
|
||||
<TextBlock Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" ToolTipService.ShowOnDisabled="True" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="{x:Type dataModel:DataModelEventViewModel}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="LightningBolt" VerticalAlignment="Center" Margin="0 0 5 0" />
|
||||
<TextBlock Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" ToolTipService.ShowOnDisabled="True" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="{x:Type dataModel:DataModelPropertyViewModel}">
|
||||
<Grid ToolTip="{Binding PropertyDescription.Description}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Value description -->
|
||||
<TextBlock Grid.Column="0" Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" ToolTipService.ShowOnDisabled="True"/>
|
||||
|
||||
<!-- Value display -->
|
||||
<StackPanel Grid.Column="1">
|
||||
<ContentControl s:View.Model="{Binding DisplayViewModel}" FontFamily="Consolas" Margin="15 0.5 0 0"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</StackPanel.Resources>
|
||||
<ContentPresenter Content="{Binding}" />
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
</ResourceDictionary>
|
||||
@@ -1,64 +0,0 @@
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Artemis.VisualScripting.ViewModel
|
||||
{
|
||||
//TODO DarthAffe 13.07.2021: What is Artemis using here?
|
||||
public abstract class AbstractBindable : INotifyPropertyChanged
|
||||
{
|
||||
#region Events
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a property value changes.
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the property already matches the desirec value or needs to be updated.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the property.</typeparam>
|
||||
/// <param name="storage">Reference to the backing-filed.</param>
|
||||
/// <param name="value">Result to apply.</param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected virtual bool RequiresUpdate<T>(ref T storage, T value)
|
||||
{
|
||||
return !Equals(storage, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the property already matches the desired value and updates it if not.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the property.</typeparam>
|
||||
/// <param name="storage">Reference to the backing-filed.</param>
|
||||
/// <param name="value">Result to apply.</param>
|
||||
/// <param name="propertyName">Name of the property used to notify listeners. This value is optional
|
||||
/// and can be provided automatically when invoked from compilers that support <see cref="CallerMemberNameAttribute"/>.</param>
|
||||
/// <returns><c>true</c> if the value was changed, <c>false</c> if the existing value matched the desired value.</returns>
|
||||
protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
|
||||
{
|
||||
if (!this.RequiresUpdate(ref storage, value)) return false;
|
||||
|
||||
storage = value;
|
||||
// ReSharper disable once ExplicitCallerInfoArgument
|
||||
this.OnPropertyChanged(propertyName);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triggers the <see cref="PropertyChanged"/>-event when a a property value has changed.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property used to notify listeners. This value is optional
|
||||
/// and can be provided automatically when invoked from compilers that support <see cref="CallerMemberNameAttribute"/>.</param>
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
using System;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Artemis.VisualScripting.ViewModel
|
||||
{
|
||||
public class ActionCommand : ICommand
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private readonly Func<bool> _canExecute;
|
||||
private readonly Action _command;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler CanExecuteChanged;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public ActionCommand(Action command, Func<bool> canExecute = null)
|
||||
{
|
||||
this._command = command;
|
||||
this._canExecute = canExecute;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public bool CanExecute(object parameter) => _canExecute?.Invoke() ?? true;
|
||||
|
||||
public void Execute(object parameter) => _command?.Invoke();
|
||||
|
||||
public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, new EventArgs());
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class ActionCommand<T> : ICommand
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private readonly Func<T, bool> _canExecute;
|
||||
private readonly Action<T> _command;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler CanExecuteChanged;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public ActionCommand(Action<T> command, Func<T, bool> canExecute = null)
|
||||
{
|
||||
this._command = command;
|
||||
this._canExecute = canExecute;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public bool CanExecute(object parameter) => _canExecute?.Invoke((T)parameter) ?? true;
|
||||
|
||||
public void Execute(object parameter) => _command?.Invoke((T)parameter);
|
||||
|
||||
public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, new EventArgs());
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,42 @@
|
||||
{
|
||||
"version": 1,
|
||||
"dependencies": {
|
||||
"net6.0-windows7.0": {
|
||||
"JetBrains.Annotations": {
|
||||
"net6.0": {
|
||||
"Avalonia": {
|
||||
"type": "Direct",
|
||||
"requested": "[2021.1.0, )",
|
||||
"resolved": "2021.1.0",
|
||||
"contentHash": "n9JSw5Z+F+6gp9vSv4aLH6p/bx3GAYA6FZVq1wJq/TJySv/kPgFKLGFeS7A8Xa5X4/GWorh5gd43yjamUgnBNA=="
|
||||
},
|
||||
"MaterialDesignThemes": {
|
||||
"type": "Direct",
|
||||
"requested": "[4.1.0, )",
|
||||
"resolved": "4.1.0",
|
||||
"contentHash": "WqrO9AbtdE4pLPtDk/C5BZRnkgWFwVGyUHWj7tRJrgnKl089DEobVXBCLeqp2mkgBeFHj4Xe3AfWyhmlnO6AZA==",
|
||||
"requested": "[0.10.13, )",
|
||||
"resolved": "0.10.13",
|
||||
"contentHash": "7st8nMai1C1nqw1a2H+zXiVYTnnfFwZz7JGziEzJK4sF6+x/W77XkdcDgDHyihcK3clQZJexYr4f+PzK4BJhSQ==",
|
||||
"dependencies": {
|
||||
"MaterialDesignColors": "2.0.1"
|
||||
"Avalonia.Remote.Protocol": "0.10.13",
|
||||
"JetBrains.Annotations": "10.3.0",
|
||||
"System.ComponentModel.Annotations": "4.5.0",
|
||||
"System.Memory": "4.5.3",
|
||||
"System.Reactive": "5.0.0",
|
||||
"System.Runtime.CompilerServices.Unsafe": "4.6.0",
|
||||
"System.ValueTuple": "4.5.0"
|
||||
}
|
||||
},
|
||||
"Avalonia.ReactiveUI": {
|
||||
"type": "Direct",
|
||||
"requested": "[0.10.13, )",
|
||||
"resolved": "0.10.13",
|
||||
"contentHash": "s5UUJ/MG97Jv9i+kxlgNSKx8Q6uJkgYMJ/LdOR3VM+7T32IRyhuxrNNCYygqk6avuJ4QqvMLU02T6v3GhI7WWA==",
|
||||
"dependencies": {
|
||||
"Avalonia": "0.10.13",
|
||||
"ReactiveUI": "13.2.10",
|
||||
"System.Reactive": "5.0.0"
|
||||
}
|
||||
},
|
||||
"Avalonia.Xaml.Behaviors": {
|
||||
"type": "Direct",
|
||||
"requested": "[0.10.13.2, )",
|
||||
"resolved": "0.10.13.2",
|
||||
"contentHash": "sZlq6FFzNNzYmHK+vARWFpxtDY4XUdnU6q6zVIm4l1iQ3/ZXor4SeUnYDdd3lFZtoJ9yc8K2g4X7d/lVEgV9tA==",
|
||||
"dependencies": {
|
||||
"Avalonia": "0.10.13",
|
||||
"Avalonia.Xaml.Interactions": "0.10.13.2",
|
||||
"Avalonia.Xaml.Interactivity": "0.10.13.2"
|
||||
}
|
||||
},
|
||||
"Ninject": {
|
||||
@@ -36,6 +58,16 @@
|
||||
"Microsoft.Extensions.ObjectPool": "5.0.9"
|
||||
}
|
||||
},
|
||||
"ReactiveUI": {
|
||||
"type": "Direct",
|
||||
"requested": "[17.1.50, )",
|
||||
"resolved": "17.1.50",
|
||||
"contentHash": "UofZH1WMwWNLvFkK2SH+gsYTkUmhFFJO0Pix9YG2RzdHQ92mRFCzHzPO1abeU8/cxzyc9hJHX7sBChzUj53Ulg==",
|
||||
"dependencies": {
|
||||
"DynamicData": "7.5.2",
|
||||
"Splat": "14.1.45"
|
||||
}
|
||||
},
|
||||
"SkiaSharp": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.88.0-preview.178, )",
|
||||
@@ -47,13 +79,128 @@
|
||||
"System.Memory": "4.5.3"
|
||||
}
|
||||
},
|
||||
"Stylet": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.3.6, )",
|
||||
"resolved": "1.3.6",
|
||||
"contentHash": "SISR+DsPrgBww3AI5FtHx1tD9VkEfJWZYu+ykq5EFM2o7Se9zxNR6FAa2g5QadQa90NKMYxn/VZEQRDo7/pdkw==",
|
||||
"Avalonia.Angle.Windows.Natives": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.0.2020091801",
|
||||
"contentHash": "nGsCPI8FuUknU/e6hZIqlsKRDxClXHZyztmgM8vuwslFC/BIV3LqM2wKefWbr6SORX4Lct4nivhSMkdF/TrKgg=="
|
||||
},
|
||||
"Avalonia.Controls.DataGrid": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.10.13",
|
||||
"contentHash": "51xcaYtJN41vX/4xUu8rNyoISTO4bdswpfZmTPjeBTdofrhZ6mzOqbxVk6tqT4gt88MPihbaPil4jsD4X4Aixw==",
|
||||
"dependencies": {
|
||||
"System.Drawing.Common": "4.6.0"
|
||||
"Avalonia": "0.10.13",
|
||||
"Avalonia.Remote.Protocol": "0.10.13",
|
||||
"JetBrains.Annotations": "10.3.0",
|
||||
"System.Reactive": "5.0.0"
|
||||
}
|
||||
},
|
||||
"Avalonia.Desktop": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.10.13",
|
||||
"contentHash": "v+siRNQYvSZR9lt/bBgb81t6LGbSC7pUo+APgPmKYGLeYcMij1O6CWk7tCh9hihMxNHYw/PEB06r8ZBQIg9YPg==",
|
||||
"dependencies": {
|
||||
"Avalonia": "0.10.13",
|
||||
"Avalonia.Native": "0.10.13",
|
||||
"Avalonia.Skia": "0.10.13",
|
||||
"Avalonia.Win32": "0.10.13",
|
||||
"Avalonia.X11": "0.10.13"
|
||||
}
|
||||
},
|
||||
"Avalonia.Diagnostics": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.10.13",
|
||||
"contentHash": "stIGj0Rv/p/Re0GqlXCc061paifG6wT0YvrTUV/fQloNctW8Y4sf1xZNzr9dxdSz6+LG2AZjdZcSUhUGOCe6Zg==",
|
||||
"dependencies": {
|
||||
"Avalonia": "0.10.13",
|
||||
"Avalonia.Controls.DataGrid": "0.10.13",
|
||||
"Microsoft.CodeAnalysis.CSharp.Scripting": "3.4.0",
|
||||
"System.Reactive": "5.0.0"
|
||||
}
|
||||
},
|
||||
"Avalonia.FreeDesktop": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.10.13",
|
||||
"contentHash": "/bKzscse/kY4RNMFk8r/jqLY/kS0fSkwp4TpqEF4UJeI8sHUvwe4yecnzNb1qDP9tCX4S6ML38LklAIqAk8gIQ==",
|
||||
"dependencies": {
|
||||
"Avalonia": "0.10.13",
|
||||
"Tmds.DBus": "0.9.0"
|
||||
}
|
||||
},
|
||||
"Avalonia.Native": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.10.13",
|
||||
"contentHash": "pq3WiiOyFyhJHnYdxP/fOlcG9DfqhJ0W5CCfPX48QyOdODbPgMF5LY6BU+McDpeAJTwQ4LqVfznHZoCeHH12gg==",
|
||||
"dependencies": {
|
||||
"Avalonia": "0.10.13"
|
||||
}
|
||||
},
|
||||
"Avalonia.Remote.Protocol": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.10.13",
|
||||
"contentHash": "hnklCHyLCMrzWjMc3T0mYkRKdfUqpw2qCkf9HBRzyqnI6uG5tLw2QIlRF9zYC4BGOpx/B/647IcIjgq6H1ypzQ=="
|
||||
},
|
||||
"Avalonia.Skia": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.10.13",
|
||||
"contentHash": "aG0JlUhCpwGM/QsN/+rRak7XlPy0Jtd5HaiCdYKtuBOc+ISGs6hmCJDKjklNANp9gZR/TUUgXkqk5VFMQUJkTA==",
|
||||
"dependencies": {
|
||||
"Avalonia": "0.10.13",
|
||||
"HarfBuzzSharp": "2.8.2-preview.178",
|
||||
"HarfBuzzSharp.NativeAssets.Linux": "2.8.2-preview.178",
|
||||
"HarfBuzzSharp.NativeAssets.WebAssembly": "2.8.2-preview.178",
|
||||
"SkiaSharp": "2.88.0-preview.178",
|
||||
"SkiaSharp.NativeAssets.Linux": "2.88.0-preview.178",
|
||||
"SkiaSharp.NativeAssets.WebAssembly": "2.88.0-preview.178"
|
||||
}
|
||||
},
|
||||
"Avalonia.Svg.Skia": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.10.12",
|
||||
"contentHash": "qsXKdm5eWpfoVPe0xgtxhbOYlhG8QdbYNJZTTihg/c4iPFYuh1G7DldiNskuVFuGiGxLVZ0g6ebql7ZkwbO1pA==",
|
||||
"dependencies": {
|
||||
"Avalonia": "0.10.12",
|
||||
"Avalonia.Skia": "0.10.12",
|
||||
"SkiaSharp": "2.88.0-preview.178",
|
||||
"Svg.Skia": "0.5.12"
|
||||
}
|
||||
},
|
||||
"Avalonia.Win32": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.10.13",
|
||||
"contentHash": "CNUGWafAonBYYbHMliujDrs4JH2giH435GxU+O1q/nGyO5Mm+PXCG4NYsg+0zwp8yQBapFK7eYwzamU+re+cDw==",
|
||||
"dependencies": {
|
||||
"Avalonia": "0.10.13",
|
||||
"Avalonia.Angle.Windows.Natives": "2.1.0.2020091801",
|
||||
"System.Drawing.Common": "4.5.0",
|
||||
"System.Numerics.Vectors": "4.5.0"
|
||||
}
|
||||
},
|
||||
"Avalonia.X11": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.10.13",
|
||||
"contentHash": "kXxn79KVB0ZfeZqQL7c2Dlvl96GBlRT8rzAh6g/j0hcgykQ55/e0be8Te6+Ny7hI+tFrob6lxvYdxYVUUCjHYg==",
|
||||
"dependencies": {
|
||||
"Avalonia": "0.10.13",
|
||||
"Avalonia.FreeDesktop": "0.10.13",
|
||||
"Avalonia.Skia": "0.10.13"
|
||||
}
|
||||
},
|
||||
"Avalonia.Xaml.Interactions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.10.13.2",
|
||||
"contentHash": "bMgr5NtEjJ/qvf+1JD4T4rRt9AbZNnJdYCx5cBfGyXHETbeliTJAt07mqTahcoPY1G2FskF1OSIW5ytljbviLw==",
|
||||
"dependencies": {
|
||||
"Avalonia": "0.10.13",
|
||||
"Avalonia.Xaml.Interactivity": "0.10.13.2"
|
||||
}
|
||||
},
|
||||
"Avalonia.Xaml.Interactivity": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.10.13.2",
|
||||
"contentHash": "OIjK5XCsUrBCqog8lxI/DEbubaNQRwy8e8Px4i3dvllomU28EYsJm4XtrPVakY7MC+we825uXY47tsO/benLug==",
|
||||
"dependencies": {
|
||||
"Avalonia": "0.10.13"
|
||||
}
|
||||
},
|
||||
"Castle.Core": {
|
||||
@@ -73,6 +220,14 @@
|
||||
"System.Xml.XmlDocument": "4.3.0"
|
||||
}
|
||||
},
|
||||
"DynamicData": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.5.4",
|
||||
"contentHash": "1OpHPoyQGzHREiP6JXnPaBBx4KWVQZW7zBAZpKXc9kl4rcbEK4fo2/T3bDXZbHWKhDqVAISW9pE4Ug9+ms3RoA==",
|
||||
"dependencies": {
|
||||
"System.Reactive": "5.0.0"
|
||||
}
|
||||
},
|
||||
"EmbedIO": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.4.3",
|
||||
@@ -81,6 +236,56 @@
|
||||
"Unosquare.Swan.Lite": "3.0.0"
|
||||
}
|
||||
},
|
||||
"Fizzler": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.2.0",
|
||||
"contentHash": "CPxuWF8EPvM0rwAtMTR5G+7EuLoGNXsEfqyx06upN9JyVALZ73KgbGn3SLFwGosifiUAXrvNHtXlUwGGytdECg=="
|
||||
},
|
||||
"FluentAvaloniaUI": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.3.0",
|
||||
"contentHash": "xzcsuOswakMpz/EdA59NEOgaCtZ/9zsd5QWTB0YYQqSv1GF95Uk2aMVtO5gtfNrCT4lZvGNWVf3HGjYz9cHovQ==",
|
||||
"dependencies": {
|
||||
"Avalonia": "0.10.13",
|
||||
"Avalonia.Desktop": "0.10.13",
|
||||
"Avalonia.Diagnostics": "0.10.13",
|
||||
"MicroCom.CodeGenerator.MSBuild": "0.10.4",
|
||||
"MicroCom.Runtime": "0.10.4"
|
||||
}
|
||||
},
|
||||
"HarfBuzzSharp": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.8.2-preview.178",
|
||||
"contentHash": "OUir5qn95QRtlc8RWKfU/63xYwtuAbylL2oAj3eBWgAsVoWnFrEv+Oh1sj0xjW7mogFGaeGtY40lqAD1srWJcQ==",
|
||||
"dependencies": {
|
||||
"HarfBuzzSharp.NativeAssets.Win32": "2.8.2-preview.178",
|
||||
"HarfBuzzSharp.NativeAssets.macOS": "2.8.2-preview.178",
|
||||
"System.Memory": "4.5.3"
|
||||
}
|
||||
},
|
||||
"HarfBuzzSharp.NativeAssets.Linux": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.8.2-preview.178",
|
||||
"contentHash": "4scihdELcRpCEubBsUMHUJn93Xvx6ASj596WfO9y8CEuFNW0LBMDL71HBCyq5zXsn8HyGjLtoBLW0PpXbVnpjQ==",
|
||||
"dependencies": {
|
||||
"HarfBuzzSharp": "2.8.2-preview.178"
|
||||
}
|
||||
},
|
||||
"HarfBuzzSharp.NativeAssets.macOS": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.8.2-preview.178",
|
||||
"contentHash": "QtmAs62il4vFtt3fFOXhhPDl7TX+NGu4tFB5qmnqUn+EnSJW7mxqNk1n9I7+Z2ORym0nTP4dhcRNtOpOS7Oenw=="
|
||||
},
|
||||
"HarfBuzzSharp.NativeAssets.WebAssembly": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.8.2-preview.178",
|
||||
"contentHash": "+S8qtBAVTrt+E85jZXPxYthUgSUq7iB6UZ0v0WFsy9gWhZ/hVE3hZJpcgeywT9H/SRX3ZIX+qzpKJlOM+mUcNA=="
|
||||
},
|
||||
"HarfBuzzSharp.NativeAssets.Win32": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.8.2-preview.178",
|
||||
"contentHash": "EgeF5uCZcAriIHmWq3hKNxz/jBJLeP/PKU4yI87UNkJCt4hYignOMjY0irl/rGVZtTL/G05xxf7TB6sjisi8sQ=="
|
||||
},
|
||||
"HidSharp": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.0",
|
||||
@@ -91,23 +296,34 @@
|
||||
"resolved": "2.11.10",
|
||||
"contentHash": "4TBsHSXPocdsEB5dewIHeKykTzIz5Ui7ouXw4JsUGI+ax4jjviVJVD7+gsPCNyA+b3de2EjYI+jcEq8I/1ZFSQ=="
|
||||
},
|
||||
"JetBrains.Annotations": {
|
||||
"type": "Transitive",
|
||||
"resolved": "10.3.0",
|
||||
"contentHash": "0GLU9lwGVXjUNlr9ZIdAgjqLI2Zm/XFGJFaqJ1T1sU+kwfeMLhm68+rblUrNUP9psRl4i8yM7Ghb4ia4oI2E5g==",
|
||||
"dependencies": {
|
||||
"System.Runtime": "4.1.0"
|
||||
}
|
||||
},
|
||||
"LiteDB": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.11",
|
||||
"contentHash": "6cL4bOmVCUB0gIK+6qIr68HeqjjHZicPDGQjvJ87mIOvkFsEsJWkIps3yoKNeLpHhJQur++yoQ9Q8gxsdos0xQ=="
|
||||
},
|
||||
"MaterialDesignColors": {
|
||||
"Material.Icons": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.0.1",
|
||||
"contentHash": "Azl8nN23SD6QPE0PdsfpKiIqWTvH7rzXwgXPiFSEt91NFOrwB5cx3iq/sbINWMZunhXJ32+jVUHiV03B8eJbZw=="
|
||||
},
|
||||
"MaterialDesignExtensions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.3.0",
|
||||
"contentHash": "dlxWtdrMH8aHNib3dWJhNQ/nNiA2b/CNvr90w/5KB6erTisuTpyYVx2l2+UGCZvwhSX5mHTHQYHfjgAKbDrgjg==",
|
||||
"resolved": "1.0.2",
|
||||
"contentHash": "4UIT91QbedjNfUYU+R3T60U+InozFtIsP1iUzGbkq/G0f1eDE3tXMWUuLEDO3yCEP2MHrPjAOpokwqk1rnWNGA==",
|
||||
"dependencies": {
|
||||
"MaterialDesignColors": "1.2.7",
|
||||
"MaterialDesignThemes": "3.2.0"
|
||||
"Newtonsoft.Json": "12.0.3"
|
||||
}
|
||||
},
|
||||
"Material.Icons.Avalonia": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.2",
|
||||
"contentHash": "hK0MQm2XyPwjT+DiviDOBjrJVQe6V0u+XTDVbxohkq58hUBlq0XZXmHHZ27jUJU6ZVP9ybu44aXfWycbVjnY2A==",
|
||||
"dependencies": {
|
||||
"Avalonia": "0.10.0",
|
||||
"Material.Icons": "1.0.2"
|
||||
}
|
||||
},
|
||||
"McMaster.NETCore.Plugins": {
|
||||
@@ -119,6 +335,85 @@
|
||||
"Microsoft.Extensions.DependencyModel": "5.0.0"
|
||||
}
|
||||
},
|
||||
"MicroCom.CodeGenerator.MSBuild": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.10.4",
|
||||
"contentHash": "aG1kLtkgX6lC8qpxVon4OFSCdWYEbQubIg+2/ychWTIFTrDHWFkhcC4YTn0IfGiVCLwh0Yj7eSc8nk5f3UoMKg=="
|
||||
},
|
||||
"MicroCom.Runtime": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.10.4",
|
||||
"contentHash": "enc2U+/1UnF3rtocxb5ofcg7cJSmJI4adbYPr8DZa5bQzvhqA/VbjlcalxoqjI3CR2RvM5WWpjKT0p3BriFJjw=="
|
||||
},
|
||||
"Microsoft.CodeAnalysis.Analyzers": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.9.6",
|
||||
"contentHash": "Kmms3TxGQMNb95Cu/3K+0bIcMnV4qf/phZBLAB0HUi65rBPxP4JO3aM2LoAcb+DFS600RQJMZ7ZLyYDTbLwJOQ=="
|
||||
},
|
||||
"Microsoft.CodeAnalysis.Common": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.4.0",
|
||||
"contentHash": "3ncA7cV+iXGA1VYwe2UEZXcvWyZSlbexWjM9AvocP7sik5UD93qt9Hq0fMRGk0jFRmvmE4T2g+bGfXiBVZEhLw==",
|
||||
"dependencies": {
|
||||
"Microsoft.CodeAnalysis.Analyzers": "2.9.6",
|
||||
"System.Collections.Immutable": "1.5.0",
|
||||
"System.Memory": "4.5.3",
|
||||
"System.Reflection.Metadata": "1.6.0",
|
||||
"System.Runtime.CompilerServices.Unsafe": "4.5.2",
|
||||
"System.Text.Encoding.CodePages": "4.5.1",
|
||||
"System.Threading.Tasks.Extensions": "4.5.3"
|
||||
}
|
||||
},
|
||||
"Microsoft.CodeAnalysis.CSharp": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.4.0",
|
||||
"contentHash": "/LsTtgcMN6Tu1oo7/WYbRAHL4/ubXC/miEakwTpcZKJKtFo7D0AK95Hw0dbGxul6C8WJu60v6NP2435TDYZM+Q==",
|
||||
"dependencies": {
|
||||
"Microsoft.CodeAnalysis.Common": "[3.4.0]"
|
||||
}
|
||||
},
|
||||
"Microsoft.CodeAnalysis.CSharp.Scripting": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.4.0",
|
||||
"contentHash": "tLgqc76qXHmONUhWhxo7z3TcL/LmGFWIUJm1exbQmVJohuQvJnejUMxmVkdxDfMuMZU1fIyJXPZ6Fkp4FEneAg==",
|
||||
"dependencies": {
|
||||
"Microsoft.CSharp": "4.3.0",
|
||||
"Microsoft.CodeAnalysis.CSharp": "[3.4.0]",
|
||||
"Microsoft.CodeAnalysis.Common": "[3.4.0]",
|
||||
"Microsoft.CodeAnalysis.Scripting.Common": "[3.4.0]"
|
||||
}
|
||||
},
|
||||
"Microsoft.CodeAnalysis.Scripting.Common": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.4.0",
|
||||
"contentHash": "+b6I3DZL2zvck+B/E/aiOveakj5U2G2BcYODQxcGh2IDbatNU3XXxGT1HumkWB5uIZI2Leu0opBgBpjScmjGMA==",
|
||||
"dependencies": {
|
||||
"Microsoft.CodeAnalysis.Common": "[3.4.0]"
|
||||
}
|
||||
},
|
||||
"Microsoft.CSharp": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.3.0",
|
||||
"contentHash": "P+MBhIM0YX+JqROuf7i306ZLJEjQYA9uUyRDE+OqwUI5sh41e2ZbPQV3LfAPh+29cmceE1pUffXsGfR4eMY3KA==",
|
||||
"dependencies": {
|
||||
"System.Collections": "4.3.0",
|
||||
"System.Diagnostics.Debug": "4.3.0",
|
||||
"System.Dynamic.Runtime": "4.3.0",
|
||||
"System.Globalization": "4.3.0",
|
||||
"System.Linq": "4.3.0",
|
||||
"System.Linq.Expressions": "4.3.0",
|
||||
"System.ObjectModel": "4.3.0",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Reflection.Extensions": "4.3.0",
|
||||
"System.Reflection.Primitives": "4.3.0",
|
||||
"System.Reflection.TypeExtensions": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0",
|
||||
"System.Runtime.InteropServices": "4.3.0",
|
||||
"System.Threading": "4.3.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.DotNet.PlatformAbstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.1.6",
|
||||
@@ -156,17 +451,12 @@
|
||||
},
|
||||
"Microsoft.Win32.SystemEvents": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.6.0",
|
||||
"contentHash": "Edg+pFW5C8WJb680Za2kTV8TqUi6Ahl/WldRVoOVJ23UQLpDHFspa+umgFjkWZw24ETsU99Cg+ErZz683M4chg==",
|
||||
"resolved": "4.5.0",
|
||||
"contentHash": "LuI1oG+24TUj1ZRQQjM5Ew73BKnZE5NZ/7eAdh1o8ST5dPhUnJvIkiIn2re3MwnkRy6ELRnvEbBxHP8uALKhJw==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "3.0.0"
|
||||
"Microsoft.NETCore.Platforms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Xaml.Behaviors.Wpf": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.1.31",
|
||||
"contentHash": "LZpuf82ACZWldmfMuv3CTUMDh3o0xo0uHUaybR5HgqVLDBJJ9RZLykplQ/bTJd0/VDt3EhD4iDgUgbdIUAM+Kg=="
|
||||
},
|
||||
"NETStandard.Library": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.6.1",
|
||||
@@ -248,6 +538,14 @@
|
||||
"Ninject": "3.3.3"
|
||||
}
|
||||
},
|
||||
"ReactiveUI.Validation": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.1",
|
||||
"contentHash": "rhEphZ4ErbGfNtbBQ/tYMsLJYHyLVyqidU+sgZ3kXKbS7QrNoM4j6PPxCwLMKsJUuvVL8JN45xgmB9tSwm7+lg==",
|
||||
"dependencies": {
|
||||
"ReactiveUI": "16.2.6"
|
||||
}
|
||||
},
|
||||
"RGB.NET.Core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.0-prerelease7",
|
||||
@@ -405,37 +703,77 @@
|
||||
"Serilog": "2.10.0"
|
||||
}
|
||||
},
|
||||
"SharpVectors.Reloaded": {
|
||||
"ShimSkiaSharp": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.7.5",
|
||||
"contentHash": "v9U5sSMGFE2zCMbh42BYHkaRYkmwwhsKMGcNRdHAKqD1ryOf4mhqnJR0o07hwg5KIEmCI9bDdrgYSmiZWlL+eA=="
|
||||
"resolved": "0.5.12",
|
||||
"contentHash": "oUGM7gQHRzbGPRs3E1pe5e8VwML21YyEz9xdo+r2ov1mAqSDPyXErVQP6pN4gnfYMVf5ADR7BVkVzt4R9Iz3gQ=="
|
||||
},
|
||||
"SkiaSharp.HarfBuzz": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.88.0-preview.178",
|
||||
"contentHash": "qTf3PbRJsTVOttQkYWOCswa1QnkH0dEOqMSgr3iXZQuKPNlj1qpGY8+OGPs25WKgUEqOpv2nog/AYQ/bpyOXzA==",
|
||||
"dependencies": {
|
||||
"HarfBuzzSharp": "2.8.2-preview.178",
|
||||
"SkiaSharp": "2.88.0-preview.178"
|
||||
}
|
||||
},
|
||||
"SkiaSharp.NativeAssets.Linux": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.88.0-preview.178",
|
||||
"contentHash": "nc9C8zGvL2G7p0lcTPhN4EOt2Mozv6KLJinMwjF97sYoI5cpkXCPZSRTcyf8k49gAZaOd+UMGaygCAz/8vaaWg==",
|
||||
"dependencies": {
|
||||
"SkiaSharp": "2.88.0-preview.178"
|
||||
}
|
||||
},
|
||||
"SkiaSharp.NativeAssets.macOS": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.88.0-preview.178",
|
||||
"contentHash": "+Hs3ku4buimzBHuc8FoyjOcE6eU5r98zcG7WH/s+doYQ1bFIjk+dKfqthgZ2o0NRAv8D3esq9rWrZTj12q+m1w=="
|
||||
},
|
||||
"SkiaSharp.NativeAssets.WebAssembly": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.88.0-preview.178",
|
||||
"contentHash": "u4Ss81oOlx0dhu5fxl4vK5f2Hm7psHDUSAoQValNV/BmixsW4TkETE3dOnHNRWwI56++tRG9dK33HimZDUrUpw=="
|
||||
},
|
||||
"SkiaSharp.NativeAssets.Win32": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.88.0-preview.178",
|
||||
"contentHash": "9og9GCkdZc/NYrmbsRzohmIBRlS1oFegJiBMsoG93qYjhh2o6q5QBYxd61zw5Mgeytl3qj4YM+6BNIF4tcF+6w=="
|
||||
},
|
||||
"SkiaSharp.Views.Desktop.Common": {
|
||||
"Splat": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.80.3",
|
||||
"contentHash": "CMQu9fr3BxGRsRryDC6lkYbYaSI2CI+RqisFX0WIdbOdbigUOLhqchmKIMb4EdFAZk13vk862qiE9v97iDZS7g==",
|
||||
"resolved": "14.1.45",
|
||||
"contentHash": "ayHdfTUklD5ci0s9m4uYMccjtkKVjZ9fVPT5q3PN+SnvyD6bjQVRozOfUHwdwh4LAz9ETZjR/tAgrm+IapXKrw=="
|
||||
},
|
||||
"Svg.Custom": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.5.12",
|
||||
"contentHash": "kmjLQf5U5WC7tRGBedUhtrOUCR0NaNL2auzOA2a/oMwEA0Bjrpd6qvMTpJUS3HITxi8vJazGl270K+i0JvdJog==",
|
||||
"dependencies": {
|
||||
"SkiaSharp": "2.80.3",
|
||||
"System.Drawing.Common": "4.5.1"
|
||||
"Fizzler": "1.2.0",
|
||||
"System.Memory": "4.5.3",
|
||||
"System.ObjectModel": "4.3.0",
|
||||
"System.ValueTuple": "4.5.0"
|
||||
}
|
||||
},
|
||||
"SkiaSharp.Views.WPF": {
|
||||
"Svg.Model": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.80.3",
|
||||
"contentHash": "oKUMm7WzFeoie6rW5nnwSGKZ94misyRsAc1wU6SEqgd6ssW17nyfohHxHuBHtmpLtIRwvjhfAu3cMLrpX/oNcw==",
|
||||
"resolved": "0.5.12",
|
||||
"contentHash": "/CPiXIugg4oVyYlQr26fB1X9iQfICALF8AJXbTWnXGoP2WZa1t6aZbAXPk3HoPApA0w5waf3XXkBiYYnWwawaQ==",
|
||||
"dependencies": {
|
||||
"SkiaSharp": "2.80.3",
|
||||
"SkiaSharp.Views.Desktop.Common": "2.80.3"
|
||||
"ShimSkiaSharp": "0.5.12",
|
||||
"Svg.Custom": "0.5.12"
|
||||
}
|
||||
},
|
||||
"Svg.Skia": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.5.12",
|
||||
"contentHash": "KjKpjz0FKge+WpRzjD1bqywAW3vZhXwpR5c7Ej5OuP4xDrQjBwtFeB0iZ+yEJMzwXf/Rs4ImuN8m3bmBDJvMHg==",
|
||||
"dependencies": {
|
||||
"SkiaSharp": "2.88.0-preview.178",
|
||||
"SkiaSharp.HarfBuzz": "2.88.0-preview.178",
|
||||
"Svg.Custom": "0.5.12",
|
||||
"Svg.Model": "0.5.12"
|
||||
}
|
||||
},
|
||||
"System.AppContext": {
|
||||
@@ -478,6 +816,11 @@
|
||||
"System.Threading.Tasks": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Collections.Immutable": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.5.0",
|
||||
"contentHash": "EXKiDFsChZW0RjrZ4FYHu9aW6+P4MCgEDCklsVseRfhoO0F+dXeMSsMRAlVXIo06kGJ/zv+2w1a2uc2+kxxSaQ=="
|
||||
},
|
||||
"System.Collections.NonGeneric": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.3.0",
|
||||
@@ -513,6 +856,11 @@
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.ComponentModel.Annotations": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.0",
|
||||
"contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg=="
|
||||
},
|
||||
"System.ComponentModel.Primitives": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.3.0",
|
||||
@@ -617,11 +965,11 @@
|
||||
},
|
||||
"System.Drawing.Common": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.6.0",
|
||||
"contentHash": "2A3spjjoPZnvpVh/sDTzd+0H8ZqTdr+hH/6obB8MMfG81EJ85PmxCKDBxhBVQiA25PliKAZ1sKogDcq9mSnFEA==",
|
||||
"resolved": "4.5.0",
|
||||
"contentHash": "AiJFxxVPdeITstiRS5aAu8+8Dpf5NawTMoapZ53Gfirml24p7HIfhjmCRxdXnmmf3IUA3AX3CcW7G73CjWxW/Q==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "3.0.0",
|
||||
"Microsoft.Win32.SystemEvents": "4.6.0"
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"Microsoft.Win32.SystemEvents": "4.5.0"
|
||||
}
|
||||
},
|
||||
"System.Dynamic.Runtime": {
|
||||
@@ -876,6 +1224,11 @@
|
||||
"System.Threading": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Reactive": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ=="
|
||||
},
|
||||
"System.Reflection": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.3.0",
|
||||
@@ -890,15 +1243,8 @@
|
||||
},
|
||||
"System.Reflection.Emit": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.3.0",
|
||||
"contentHash": "228FG0jLcIwTVJyz8CLFKueVqQK36ANazUManGaJHkO0icjiIypKW7YLWLIWahyIkdh5M7mV2dJepllLyA1SKg==",
|
||||
"dependencies": {
|
||||
"System.IO": "4.3.0",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Reflection.Emit.ILGeneration": "4.3.0",
|
||||
"System.Reflection.Primitives": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
"resolved": "4.7.0",
|
||||
"contentHash": "VR4kk8XLKebQ4MZuKuIni/7oh+QGFmZW3qORd1GvBq/8026OpW501SzT/oypwiQl4TvT8ErnReh/NzY9u+C6wQ=="
|
||||
},
|
||||
"System.Reflection.Emit.ILGeneration": {
|
||||
"type": "Transitive",
|
||||
@@ -977,6 +1323,11 @@
|
||||
"Microsoft.NETCore.Targets": "1.1.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.CompilerServices.Unsafe": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.6.0",
|
||||
"contentHash": "HxozeSlipUK7dAroTYwIcGwKDeOVpQnJlpVaOkBz7CM4TsE5b/tKlQBZecTjh6FzcSbxndYaxxpsBMz+wMJeyw=="
|
||||
},
|
||||
"System.Runtime.Extensions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.3.0",
|
||||
@@ -1203,6 +1554,15 @@
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Text.Encoding.CodePages": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.1",
|
||||
"contentHash": "4J2JQXbftjPMppIHJ7IC+VXQ9XfEagN92vZZNoG12i+zReYlim5dMoXFC1Zzg7tsnKDM7JPo5bYfFK4Jheq44w==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.1.2",
|
||||
"System.Runtime.CompilerServices.Unsafe": "4.5.2"
|
||||
}
|
||||
},
|
||||
"System.Text.Encoding.Extensions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.3.0",
|
||||
@@ -1243,13 +1603,8 @@
|
||||
},
|
||||
"System.Threading.Tasks.Extensions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.3.0",
|
||||
"contentHash": "npvJkVKl5rKXrtl1Kkm6OhOUaYGEiF9wFbppFRWSMoApKzt2PiPHT2Bb8a5sAWxprvdOAtvaARS9QYMznEUtug==",
|
||||
"dependencies": {
|
||||
"System.Collections": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Threading.Tasks": "4.3.0"
|
||||
}
|
||||
"resolved": "4.5.3",
|
||||
"contentHash": "+MvhNtcvIbqmhANyKu91jQnvIRVSTiaOiFNfKWwXGHG48YAb4I/TyH8spsySiPYla7gKal5ZnF3teJqZAximyQ=="
|
||||
},
|
||||
"System.Threading.Timer": {
|
||||
"type": "Transitive",
|
||||
@@ -1324,6 +1679,15 @@
|
||||
"System.Xml.ReaderWriter": "4.3.0"
|
||||
}
|
||||
},
|
||||
"Tmds.DBus": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.9.0",
|
||||
"contentHash": "KcTWL9aKuob9Qo2sOTTKFePs1rKGTwZrcBvMFuGVIVR5RojX3oIFj5UBLYfSGjYgrcImC7LjQI3DdCFwUnhNXw==",
|
||||
"dependencies": {
|
||||
"System.Reflection.Emit": "4.7.0",
|
||||
"System.Security.Principal.Windows": "4.7.0"
|
||||
}
|
||||
},
|
||||
"Unosquare.Swan.Lite": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.0.0",
|
||||
@@ -1368,19 +1732,17 @@
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Artemis.Core": "1.0.0",
|
||||
"Humanizer.Core": "2.11.10",
|
||||
"MaterialDesignExtensions": "3.3.0",
|
||||
"MaterialDesignThemes": "4.1.0",
|
||||
"Microsoft.Xaml.Behaviors.Wpf": "1.1.31",
|
||||
"Ninject": "3.3.4",
|
||||
"Ninject.Extensions.Conventions": "3.3.0",
|
||||
"Avalonia": "0.10.13",
|
||||
"Avalonia.ReactiveUI": "0.10.13",
|
||||
"Avalonia.Svg.Skia": "0.10.12",
|
||||
"Avalonia.Xaml.Behaviors": "0.10.13.2",
|
||||
"DynamicData": "7.5.4",
|
||||
"FluentAvaloniaUI": "1.3.0",
|
||||
"Material.Icons.Avalonia": "1.0.2",
|
||||
"RGB.NET.Core": "1.0.0-prerelease7",
|
||||
"SharpVectors.Reloaded": "1.7.5",
|
||||
"SkiaSharp": "2.88.0-preview.178",
|
||||
"SkiaSharp.Views.WPF": "2.80.3",
|
||||
"Stylet": "1.3.6",
|
||||
"System.Buffers": "4.5.1",
|
||||
"System.Numerics.Vectors": "4.5.0"
|
||||
"ReactiveUI": "17.1.50",
|
||||
"ReactiveUI.Validation": "2.2.1",
|
||||
"SkiaSharp": "2.88.0-preview.178"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user