mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Merge branch 'development'
This commit is contained in:
commit
5a571f09d7
13
.github/workflows/nuget.yml
vendored
13
.github/workflows/nuget.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
|||||||
version:
|
version:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
version-suffix: ${{ steps.get-version.outputs.version-suffix }}
|
version-number: ${{ steps.get-version.outputs.version-number }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@ -22,9 +22,12 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
$MidnightUtc = [DateTime]::UtcNow.Date
|
$MidnightUtc = [DateTime]::UtcNow.Date
|
||||||
$BranchName = "${{ github.ref_name }}".replace('/','-').replace('.','-')
|
$BranchName = "${{ github.ref_name }}".replace('/','-').replace('.','-')
|
||||||
|
$ApiVersion = (Select-Xml -Path 'src/Artemis.Core/Artemis.Core.csproj' -XPath '//PluginApiVersion').Node.InnerText
|
||||||
$NumberOfCommitsToday = (git log --after=$($MidnightUtc.ToString("o")) --oneline | Measure-Object -Line).Lines
|
$NumberOfCommitsToday = (git log --after=$($MidnightUtc.ToString("o")) --oneline | Measure-Object -Line).Lines
|
||||||
$VersionSuffix = "$BranchName.$($MidnightUtc.ToString("yyyyMMdd")).$NumberOfCommitsToday"
|
$VersionNumber = "$ApiVersion.$($MidnightUtc.ToString("yyyy.MMdd")).$NumberOfCommitsToday"
|
||||||
Write-Output "::set-output name=version-suffix::$VersionSuffix"
|
# If we're not in master, add the branch name to the version so it counts as prerelease
|
||||||
|
if ($BranchName -ne "master") { $VersionNumber += "-$BranchName" }
|
||||||
|
Write-Output "::set-output name=version-number::$VersionNumber"
|
||||||
|
|
||||||
nuget:
|
nuget:
|
||||||
name: Publish Nuget Packages
|
name: Publish Nuget Packages
|
||||||
@ -38,8 +41,8 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
- name: Pack Artemis.Core
|
- name: Pack Artemis.Core
|
||||||
run: dotnet pack -c Release -p:VersionSuffix=${{ needs.version.outputs.version-suffix }} -p:BuildingNuget=True src/Artemis.Core/Artemis.Core.csproj
|
run: dotnet pack -c Release -p:Version=${{ needs.version.outputs.version-number }} -p:BuildingNuget=True src/Artemis.Core/Artemis.Core.csproj
|
||||||
- name: Pack Artemis.UI.Shared
|
- name: Pack Artemis.UI.Shared
|
||||||
run: dotnet pack -c Release -p:VersionSuffix=${{ needs.version.outputs.version-suffix }} src/Artemis.UI.Shared/Artemis.UI.Shared.csproj
|
run: dotnet pack -c Release -p:Version=${{ needs.version.outputs.version-number }} src/Artemis.UI.Shared/Artemis.UI.Shared.csproj
|
||||||
- name: Push Nugets
|
- name: Push Nugets
|
||||||
run: dotnet nuget push **/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
run: dotnet nuget push **/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
||||||
@ -10,13 +10,18 @@
|
|||||||
<Platforms>x64</Platforms>
|
<Platforms>x64</Platforms>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<PackageId>ArtemisRGB.Core</PackageId>
|
<PackageId>ArtemisRGB.Core</PackageId>
|
||||||
<!-- API Version -->
|
<PluginApiVersion>1</PluginApiVersion>
|
||||||
<VersionPrefix>1.0.0.0</VersionPrefix>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Artemis.Storage\Artemis.Storage.csproj"/>
|
<!--Used to embed the above PluginApiVersion property into the assembly as metadata-->
|
||||||
<ProjectReference Condition="'$(BuildingNuget)' == 'True'" Update="..\Artemis.Storage\Artemis.Storage.csproj" PrivateAssets="All"/>
|
<AssemblyMetadata Include="PluginApiVersion" Value="$(PluginApiVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Artemis.Storage\Artemis.Storage.csproj" />
|
||||||
|
<ProjectReference Condition="'$(BuildingNuget)' == 'True'" Update="..\Artemis.Storage\Artemis.Storage.csproj" PrivateAssets="All" />
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Include Artemis.Storage directly in the NuGet package instead of expecting it as an external dependency
|
Include Artemis.Storage directly in the NuGet package instead of expecting it as an external dependency
|
||||||
|
|||||||
@ -2,6 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Artemis.Core.JsonConverters;
|
using Artemis.Core.JsonConverters;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
@ -61,7 +62,8 @@ public static class Constants
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current API version for plugins
|
/// The current API version for plugins
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly Version PluginApi = CoreAssembly.GetName().Version!;
|
public static readonly int PluginApiVersion = int.Parse(CoreAssembly.GetCustomAttributes<AssemblyMetadataAttribute>()
|
||||||
|
.First(a => a.Key == "PluginApiVersion").Value);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The plugin info used by core components of Artemis
|
/// The plugin info used by core components of Artemis
|
||||||
|
|||||||
@ -16,12 +16,13 @@ namespace Artemis.Core;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class Layer : RenderProfileElement
|
public sealed class Layer : RenderProfileElement
|
||||||
{
|
{
|
||||||
private readonly List<Layer> _renderCopies;
|
private readonly List<Layer> _renderCopies = new();
|
||||||
private LayerGeneralProperties _general;
|
private LayerGeneralProperties _general = new();
|
||||||
|
private LayerTransformProperties _transform = new();
|
||||||
private BaseLayerBrush? _layerBrush;
|
private BaseLayerBrush? _layerBrush;
|
||||||
private LayerShape? _layerShape;
|
private LayerShape? _layerShape;
|
||||||
private List<ArtemisLed> _leds;
|
private List<ArtemisLed> _leds = new();
|
||||||
private LayerTransformProperties _transform;
|
private List<LedEntity> _missingLeds = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the <see cref="Layer" /> class and adds itself to the child collection of the provided
|
/// Creates a new instance of the <see cref="Layer" /> class and adds itself to the child collection of the provided
|
||||||
@ -37,16 +38,9 @@ public sealed class Layer : RenderProfileElement
|
|||||||
Profile = Parent.Profile;
|
Profile = Parent.Profile;
|
||||||
Name = name;
|
Name = name;
|
||||||
Suspended = false;
|
Suspended = false;
|
||||||
|
|
||||||
// TODO: move to top
|
|
||||||
_renderCopies = new List<Layer>();
|
|
||||||
_general = new LayerGeneralProperties();
|
|
||||||
_transform = new LayerTransformProperties();
|
|
||||||
|
|
||||||
_leds = new List<ArtemisLed>();
|
|
||||||
Leds = new ReadOnlyCollection<ArtemisLed>(_leds);
|
Leds = new ReadOnlyCollection<ArtemisLed>(_leds);
|
||||||
|
|
||||||
Adapter = new LayerAdapter(this);
|
Adapter = new LayerAdapter(this);
|
||||||
|
|
||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,16 +57,9 @@ public sealed class Layer : RenderProfileElement
|
|||||||
|
|
||||||
Profile = profile;
|
Profile = profile;
|
||||||
Parent = parent;
|
Parent = parent;
|
||||||
|
|
||||||
// TODO: move to top
|
|
||||||
_renderCopies = new List<Layer>();
|
|
||||||
_general = new LayerGeneralProperties();
|
|
||||||
_transform = new LayerTransformProperties();
|
|
||||||
|
|
||||||
_leds = new List<ArtemisLed>();
|
|
||||||
Leds = new ReadOnlyCollection<ArtemisLed>(_leds);
|
Leds = new ReadOnlyCollection<ArtemisLed>(_leds);
|
||||||
|
|
||||||
Adapter = new LayerAdapter(this);
|
Adapter = new LayerAdapter(this);
|
||||||
|
|
||||||
Load();
|
Load();
|
||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
@ -327,6 +314,7 @@ public sealed class Layer : RenderProfileElement
|
|||||||
|
|
||||||
// LEDs
|
// LEDs
|
||||||
LayerEntity.Leds.Clear();
|
LayerEntity.Leds.Clear();
|
||||||
|
SaveMissingLeds();
|
||||||
foreach (ArtemisLed artemisLed in Leds)
|
foreach (ArtemisLed artemisLed in Leds)
|
||||||
{
|
{
|
||||||
LedEntity ledEntity = new()
|
LedEntity ledEntity = new()
|
||||||
@ -786,6 +774,8 @@ public sealed class Layer : RenderProfileElement
|
|||||||
a.RgbLed.Id.ToString() == ledEntity.LedName);
|
a.RgbLed.Id.ToString() == ledEntity.LedName);
|
||||||
if (match != null)
|
if (match != null)
|
||||||
leds.Add(match);
|
leds.Add(match);
|
||||||
|
else
|
||||||
|
_missingLeds.Add(ledEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
_leds = leds;
|
_leds = leds;
|
||||||
@ -793,6 +783,11 @@ public sealed class Layer : RenderProfileElement
|
|||||||
CalculateRenderProperties();
|
CalculateRenderProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SaveMissingLeds()
|
||||||
|
{
|
||||||
|
LayerEntity.Leds.AddRange(_missingLeds.Except(LayerEntity.Leds, LedEntity.LedEntityComparer));
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Brush management
|
#region Brush management
|
||||||
|
|||||||
@ -191,7 +191,7 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a boolean indicating whether this plugin is compatible with the current operating system and API version
|
/// Gets a boolean indicating whether this plugin is compatible with the current operating system and API version
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsCompatible => Platforms.MatchesCurrentOperatingSystem() && Api != null && Api >= Constants.PluginApi;
|
public bool IsCompatible => Platforms.MatchesCurrentOperatingSystem() && Api != null && Api.Major >= Constants.PluginApiVersion;
|
||||||
|
|
||||||
internal string PreferredPluginDirectory => $"{Main.Split(".dll")[0].Replace("/", "").Replace("\\", "")}-{Guid.ToString().Substring(0, 8)}";
|
internal string PreferredPluginDirectory => $"{Main.Split(".dll")[0].Replace("/", "").Replace("\\", "")}-{Guid.ToString().Substring(0, 8)}";
|
||||||
|
|
||||||
|
|||||||
@ -75,8 +75,9 @@ internal class NodeService : INodeService
|
|||||||
string name = nodeAttribute?.Name ?? nodeType.Name;
|
string name = nodeAttribute?.Name ?? nodeType.Name;
|
||||||
string description = nodeAttribute?.Description ?? string.Empty;
|
string description = nodeAttribute?.Description ?? string.Empty;
|
||||||
string category = nodeAttribute?.Category ?? string.Empty;
|
string category = nodeAttribute?.Category ?? string.Empty;
|
||||||
|
string helpUrl = nodeAttribute?.HelpUrl ?? string.Empty;
|
||||||
|
|
||||||
NodeData nodeData = new(plugin, nodeType, name, description, category, nodeAttribute?.InputType, nodeAttribute?.OutputType, (s, e) => CreateNode(s, e, nodeType));
|
NodeData nodeData = new(plugin, nodeType, name, description, category, helpUrl, nodeAttribute?.InputType, nodeAttribute?.OutputType, (s, e) => CreateNode(s, e, nodeType));
|
||||||
return NodeTypeStore.Add(nodeData);
|
return NodeTypeStore.Add(nodeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,12 +18,12 @@ public interface INode : INotifyPropertyChanged, IBreakableModel
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the name of the node
|
/// Gets the name of the node
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Name { get; }
|
string Name { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the description of the node
|
/// Gets the description of the node
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Description { get; }
|
string Description { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a boolean indicating whether the node is the exit node of the script
|
/// Gets a boolean indicating whether the node is the exit node of the script
|
||||||
@ -45,6 +45,11 @@ public interface INode : INotifyPropertyChanged, IBreakableModel
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public double Y { get; set; }
|
public double Y { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the help URL of the node
|
||||||
|
/// </summary>
|
||||||
|
string HelpUrl { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a read-only collection of the pins on this node
|
/// Gets a read-only collection of the pins on this node
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -24,6 +24,11 @@ public class NodeAttribute : Attribute
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Category { get; } = string.Empty;
|
public string Category { get; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the help URL of the node
|
||||||
|
/// </summary>
|
||||||
|
public string HelpUrl { get; init; } = string.Empty;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the primary input type of the node
|
/// Gets the primary input type of the node
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -65,5 +70,16 @@ public class NodeAttribute : Attribute
|
|||||||
Category = category;
|
Category = category;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="NodeAttribute" /> class
|
||||||
|
/// </summary>
|
||||||
|
public NodeAttribute(string name, string description, string category, string helpUrl)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Description = description;
|
||||||
|
Category = category;
|
||||||
|
HelpUrl = helpUrl;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using Artemis.Storage.Entities.Profile.Nodes;
|
using Artemis.Storage.Entities.Profile.Nodes;
|
||||||
|
using Castle.Core.Internal;
|
||||||
|
|
||||||
namespace Artemis.Core;
|
namespace Artemis.Core;
|
||||||
|
|
||||||
@ -10,13 +11,14 @@ public class NodeData
|
|||||||
{
|
{
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
internal NodeData(Plugin plugin, Type type, string name, string description, string category, Type? inputType, Type? outputType, Func<INodeScript, NodeEntity?, INode> create)
|
internal NodeData(Plugin plugin, Type type, string name, string description, string category, string helpUrl, Type? inputType, Type? outputType, Func<INodeScript, NodeEntity?, INode> create)
|
||||||
{
|
{
|
||||||
Plugin = plugin;
|
Plugin = plugin;
|
||||||
Type = type;
|
Type = type;
|
||||||
Name = name;
|
Name = name;
|
||||||
Description = description;
|
Description = description;
|
||||||
Category = category;
|
Category = category;
|
||||||
|
HelpUrl = helpUrl;
|
||||||
InputType = inputType;
|
InputType = inputType;
|
||||||
OutputType = outputType;
|
OutputType = outputType;
|
||||||
_create = create;
|
_create = create;
|
||||||
@ -34,7 +36,15 @@ public class NodeData
|
|||||||
/// <returns>The returning node of type <see cref="Type" /></returns>
|
/// <returns>The returning node of type <see cref="Type" /></returns>
|
||||||
public INode CreateNode(INodeScript script, NodeEntity? entity)
|
public INode CreateNode(INodeScript script, NodeEntity? entity)
|
||||||
{
|
{
|
||||||
return _create(script, entity);
|
INode node = _create(script, entity);
|
||||||
|
if (string.IsNullOrWhiteSpace(node.Name))
|
||||||
|
node.Name = Name;
|
||||||
|
if (string.IsNullOrWhiteSpace(node.Description))
|
||||||
|
node.Description = Description;
|
||||||
|
if (string.IsNullOrWhiteSpace(node.HelpUrl))
|
||||||
|
node.HelpUrl = HelpUrl;
|
||||||
|
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -101,6 +111,11 @@ public class NodeData
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Category { get; }
|
public string Category { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the help URL of the node this data represents
|
||||||
|
/// </summary>
|
||||||
|
public string HelpUrl { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the primary input type of the node this data represents
|
/// Gets the primary input type of the node this data represents
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -46,7 +46,7 @@ public abstract class Node : BreakableModel, INode
|
|||||||
public string Name
|
public string Name
|
||||||
{
|
{
|
||||||
get => _name;
|
get => _name;
|
||||||
protected set => SetAndNotify(ref _name, value);
|
set => SetAndNotify(ref _name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string _description;
|
private string _description;
|
||||||
@ -55,7 +55,7 @@ public abstract class Node : BreakableModel, INode
|
|||||||
public string Description
|
public string Description
|
||||||
{
|
{
|
||||||
get => _description;
|
get => _description;
|
||||||
protected set => SetAndNotify(ref _description, value);
|
set => SetAndNotify(ref _description, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private double _x;
|
private double _x;
|
||||||
@ -76,6 +76,13 @@ public abstract class Node : BreakableModel, INode
|
|||||||
set => SetAndNotify(ref _y, value);
|
set => SetAndNotify(ref _y, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string HelpUrl
|
||||||
|
{
|
||||||
|
get => _helpUrl;
|
||||||
|
set => SetAndNotify(ref _helpUrl, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual bool IsExitNode => false;
|
public virtual bool IsExitNode => false;
|
||||||
|
|
||||||
@ -88,6 +95,7 @@ public abstract class Node : BreakableModel, INode
|
|||||||
public IReadOnlyCollection<IPin> Pins => new ReadOnlyCollection<IPin>(_pins);
|
public IReadOnlyCollection<IPin> Pins => new ReadOnlyCollection<IPin>(_pins);
|
||||||
|
|
||||||
private readonly List<IPinCollection> _pinCollections = new();
|
private readonly List<IPinCollection> _pinCollections = new();
|
||||||
|
private string _helpUrl;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IReadOnlyCollection<IPinCollection> PinCollections => new ReadOnlyCollection<IPinCollection>(_pinCollections);
|
public IReadOnlyCollection<IPinCollection> PinCollections => new ReadOnlyCollection<IPinCollection>(_pinCollections);
|
||||||
@ -106,6 +114,7 @@ public abstract class Node : BreakableModel, INode
|
|||||||
{
|
{
|
||||||
_name = string.Empty;
|
_name = string.Empty;
|
||||||
_description = string.Empty;
|
_description = string.Empty;
|
||||||
|
_helpUrl = string.Empty;
|
||||||
_id = Guid.NewGuid();
|
_id = Guid.NewGuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,6 +125,7 @@ public abstract class Node : BreakableModel, INode
|
|||||||
{
|
{
|
||||||
_name = name;
|
_name = name;
|
||||||
_description = description;
|
_description = description;
|
||||||
|
_helpUrl = string.Empty;
|
||||||
_id = Guid.NewGuid();
|
_id = Guid.NewGuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,37 @@
|
|||||||
namespace Artemis.Storage.Entities.Profile;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Entities.Profile;
|
||||||
|
|
||||||
public class LedEntity
|
public class LedEntity
|
||||||
{
|
{
|
||||||
|
#region LedEntityEqualityComparer
|
||||||
|
|
||||||
|
private sealed class LedEntityEqualityComparer : IEqualityComparer<LedEntity>
|
||||||
|
{
|
||||||
|
public bool Equals(LedEntity x, LedEntity y)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(x, y))
|
||||||
|
return true;
|
||||||
|
if (ReferenceEquals(x, null))
|
||||||
|
return false;
|
||||||
|
if (ReferenceEquals(y, null))
|
||||||
|
return false;
|
||||||
|
if (x.GetType() != y.GetType())
|
||||||
|
return false;
|
||||||
|
return x.LedName == y.LedName && x.DeviceIdentifier == y.DeviceIdentifier && x.PhysicalLayout == y.PhysicalLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetHashCode(LedEntity obj)
|
||||||
|
{
|
||||||
|
return HashCode.Combine(obj.LedName, obj.DeviceIdentifier, obj.PhysicalLayout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEqualityComparer<LedEntity> LedEntityComparer { get; } = new LedEntityEqualityComparer();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
public string LedName { get; set; }
|
public string LedName { get; set; }
|
||||||
public string DeviceIdentifier { get; set; }
|
public string DeviceIdentifier { get; set; }
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,22 @@ namespace Artemis.Storage.Entities.Profile.Nodes;
|
|||||||
|
|
||||||
public class NodeConnectionEntity
|
public class NodeConnectionEntity
|
||||||
{
|
{
|
||||||
|
public NodeConnectionEntity()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeConnectionEntity(NodeConnectionEntity nodeConnectionEntity)
|
||||||
|
{
|
||||||
|
SourceType = nodeConnectionEntity.SourceType;
|
||||||
|
SourceNode = nodeConnectionEntity.SourceNode;
|
||||||
|
TargetNode = nodeConnectionEntity.TargetNode;
|
||||||
|
SourcePinCollectionId = nodeConnectionEntity.SourcePinCollectionId;
|
||||||
|
SourcePinId = nodeConnectionEntity.SourcePinId;
|
||||||
|
TargetType = nodeConnectionEntity.TargetType;
|
||||||
|
TargetPinCollectionId = nodeConnectionEntity.TargetPinCollectionId;
|
||||||
|
TargetPinId = nodeConnectionEntity.TargetPinId;
|
||||||
|
}
|
||||||
|
|
||||||
public string SourceType { get; set; }
|
public string SourceType { get; set; }
|
||||||
public Guid SourceNode { get; set; }
|
public Guid SourceNode { get; set; }
|
||||||
public Guid TargetNode { get; set; }
|
public Guid TargetNode { get; set; }
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Artemis.Storage.Entities.Profile.Nodes;
|
namespace Artemis.Storage.Entities.Profile.Nodes;
|
||||||
|
|
||||||
@ -10,6 +11,22 @@ public class NodeEntity
|
|||||||
PinCollections = new List<NodePinCollectionEntity>();
|
PinCollections = new List<NodePinCollectionEntity>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NodeEntity(NodeEntity nodeEntity)
|
||||||
|
{
|
||||||
|
Id = nodeEntity.Id;
|
||||||
|
Type = nodeEntity.Type;
|
||||||
|
PluginId = nodeEntity.PluginId;
|
||||||
|
|
||||||
|
Name = nodeEntity.Name;
|
||||||
|
Description = nodeEntity.Description;
|
||||||
|
IsExitNode = nodeEntity.IsExitNode;
|
||||||
|
X = nodeEntity.X;
|
||||||
|
Y = nodeEntity.Y;
|
||||||
|
Storage = nodeEntity.Storage;
|
||||||
|
|
||||||
|
PinCollections = nodeEntity.PinCollections.Select(p => new NodePinCollectionEntity(p)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public string Type { get; set; }
|
public string Type { get; set; }
|
||||||
public Guid PluginId { get; set; }
|
public Guid PluginId { get; set; }
|
||||||
|
|||||||
@ -2,6 +2,17 @@
|
|||||||
|
|
||||||
public class NodePinCollectionEntity
|
public class NodePinCollectionEntity
|
||||||
{
|
{
|
||||||
|
public NodePinCollectionEntity()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodePinCollectionEntity(NodePinCollectionEntity nodePinCollectionEntity)
|
||||||
|
{
|
||||||
|
Id = nodePinCollectionEntity.Id;
|
||||||
|
Direction = nodePinCollectionEntity.Direction;
|
||||||
|
Amount = nodePinCollectionEntity.Amount;
|
||||||
|
}
|
||||||
|
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public int Direction { set; get; }
|
public int Direction { set; get; }
|
||||||
public int Amount { get; set; }
|
public int Amount { get; set; }
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
|
|
||||||
namespace Artemis.UI.Shared.Services.NodeEditor.Commands;
|
namespace Artemis.UI.Shared.Services.NodeEditor.Commands;
|
||||||
@ -36,7 +37,8 @@ public class AddNode : INodeEditorCommand, IDisposable
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Execute()
|
public void Execute()
|
||||||
{
|
{
|
||||||
_nodeScript.AddNode(_node);
|
if (!_nodeScript.Nodes.Contains(_node))
|
||||||
|
_nodeScript.AddNode(_node);
|
||||||
_isRemoved = false;
|
_isRemoved = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -45,7 +45,7 @@
|
|||||||
|
|
||||||
<!-- Add Styles Here -->
|
<!-- Add Styles Here -->
|
||||||
<Style Selector="TextBox.condensed">
|
<Style Selector="TextBox.condensed">
|
||||||
<Setter Property="Padding" Value="2" />
|
<Setter Property="Padding" Value="6 1" />
|
||||||
<Setter Property="FontSize" Value="13" />
|
<Setter Property="FontSize" Value="13" />
|
||||||
<Setter Property="MinHeight" Value="24" />
|
<Setter Property="MinHeight" Value="24" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|||||||
@ -10,7 +10,8 @@
|
|||||||
<!-- Add Controls for Previewer Here -->
|
<!-- Add Controls for Previewer Here -->
|
||||||
<TextBox Text="99999999"
|
<TextBox Text="99999999"
|
||||||
attached:TextBoxAssist.PrefixText="%"
|
attached:TextBoxAssist.PrefixText="%"
|
||||||
attached:TextBoxAssist.SuffixText="%"></TextBox>
|
attached:TextBoxAssist.SuffixText="%">
|
||||||
|
</TextBox>
|
||||||
<controls:NumberBox Value="99999999"
|
<controls:NumberBox Value="99999999"
|
||||||
attached:NumberBoxAssist.PrefixText="%"
|
attached:NumberBoxAssist.PrefixText="%"
|
||||||
attached:NumberBoxAssist.SuffixText="%" />
|
attached:NumberBoxAssist.SuffixText="%" />
|
||||||
@ -30,80 +31,95 @@
|
|||||||
|
|
||||||
<!-- Add Styles Here -->
|
<!-- Add Styles Here -->
|
||||||
<Style Selector="TextBox">
|
<Style Selector="TextBox">
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<ControlTemplate>
|
<ControlTemplate>
|
||||||
<DataValidationErrors>
|
<DataValidationErrors>
|
||||||
<Panel>
|
<Panel>
|
||||||
<!-- This is flipped (scaleY(-1)) for the elevation brush effect
|
<!-- This is flipped (scaleY(-1)) for the elevation brush effect
|
||||||
-->
|
-->
|
||||||
<Border
|
<Border
|
||||||
Name="PART_BorderElement"
|
Name="PART_BorderElement"
|
||||||
Background="{TemplateBinding Background}"
|
Background="{TemplateBinding Background}"
|
||||||
BorderBrush="{TemplateBinding BorderBrush}"
|
BorderBrush="{TemplateBinding BorderBrush}"
|
||||||
BorderThickness="{TemplateBinding BorderThickness}"
|
BorderThickness="{TemplateBinding BorderThickness}"
|
||||||
MinWidth="{TemplateBinding MinWidth}"
|
MinWidth="{TemplateBinding MinWidth}"
|
||||||
MinHeight="{TemplateBinding MinHeight}"
|
MinHeight="{TemplateBinding MinHeight}"
|
||||||
RenderTransform="scaleY(-1)"
|
RenderTransform="scaleY(-1)"
|
||||||
CornerRadius="{TemplateBinding CornerRadius}"/>
|
CornerRadius="{TemplateBinding CornerRadius}" />
|
||||||
|
|
||||||
<Border
|
<Border
|
||||||
Margin="{TemplateBinding BorderThickness}">
|
Margin="{TemplateBinding BorderThickness}">
|
||||||
<Grid ColumnDefinitions="Auto,*,Auto" >
|
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||||
<ContentPresenter Grid.Column="0" Content="{TemplateBinding InnerLeftContent}"/>
|
<ContentPresenter Grid.Column="0" Content="{TemplateBinding InnerLeftContent}" />
|
||||||
<DockPanel x:Name="PART_InnerDockPanel" Grid.Column="1" Margin="{TemplateBinding Padding}">
|
<Grid x:Name="PART_InnerGrid"
|
||||||
<TextBlock Name="PART_Prefix"
|
Grid.Column="1"
|
||||||
Text="{TemplateBinding attached:TextBoxAssist.PrefixText}"
|
RowDefinitions="Auto,Auto"
|
||||||
IsHitTestVisible="False"
|
ColumnDefinitions="Auto,*,Auto"
|
||||||
DockPanel.Dock="Left"/>
|
Cursor="IBeam"
|
||||||
<TextBlock Name="PART_FloatingWatermark"
|
Margin="{TemplateBinding Padding}">
|
||||||
|
<TextBlock Grid.Row="0"
|
||||||
|
Grid.ColumnSpan="3"
|
||||||
|
Name="PART_FloatingWatermark"
|
||||||
Foreground="{DynamicResource SystemAccentColor}"
|
Foreground="{DynamicResource SystemAccentColor}"
|
||||||
FontSize="{TemplateBinding FontSize}"
|
FontSize="{TemplateBinding FontSize}"
|
||||||
Text="{TemplateBinding Watermark}"
|
Text="{TemplateBinding Watermark}" />
|
||||||
DockPanel.Dock="Top" />
|
|
||||||
<ScrollViewer HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
|
|
||||||
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}">
|
|
||||||
<Panel>
|
|
||||||
<TextBlock Name="PART_Watermark"
|
|
||||||
Text="{TemplateBinding Watermark}"
|
|
||||||
TextAlignment="{TemplateBinding TextAlignment}"
|
|
||||||
TextWrapping="{TemplateBinding TextWrapping}"
|
|
||||||
IsVisible="{TemplateBinding Text, Converter={x:Static StringConverters.IsNullOrEmpty}}"
|
|
||||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
|
||||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
|
||||||
IsHitTestVisible="False"/>
|
|
||||||
<TextPresenter Name="PART_TextPresenter"
|
|
||||||
Text="{TemplateBinding Text, Mode=TwoWay}"
|
|
||||||
CaretIndex="{TemplateBinding CaretIndex}"
|
|
||||||
SelectionStart="{TemplateBinding SelectionStart}"
|
|
||||||
SelectionEnd="{TemplateBinding SelectionEnd}"
|
|
||||||
TextAlignment="{TemplateBinding TextAlignment}"
|
|
||||||
TextWrapping="{TemplateBinding TextWrapping}"
|
|
||||||
PasswordChar="{TemplateBinding PasswordChar}"
|
|
||||||
RevealPassword="{TemplateBinding RevealPassword}"
|
|
||||||
SelectionBrush="{TemplateBinding SelectionBrush}"
|
|
||||||
SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}"
|
|
||||||
CaretBrush="{TemplateBinding CaretBrush}"
|
|
||||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
|
||||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
|
|
||||||
</Panel>
|
|
||||||
</ScrollViewer>
|
|
||||||
|
|
||||||
<TextBlock Name="PART_Suffix"
|
<TextBlock Grid.Row="1"
|
||||||
Text="{TemplateBinding attached:TextBoxAssist.SuffixText}"
|
Grid.Column="0"
|
||||||
|
Name="PART_Prefix"
|
||||||
|
Text="{TemplateBinding attached:TextBoxAssist.PrefixText}"
|
||||||
|
IsVisible="{TemplateBinding attached:TextBoxAssist.PrefixText, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||||
IsHitTestVisible="False"
|
IsHitTestVisible="False"
|
||||||
HorizontalAlignment="Right"
|
DockPanel.Dock="Left" />
|
||||||
DockPanel.Dock="Right"/>
|
|
||||||
</DockPanel>
|
<ScrollViewer Grid.Row="1"
|
||||||
<ContentPresenter Grid.Column="2" Content="{TemplateBinding InnerRightContent}"/>
|
Grid.Column="1"
|
||||||
</Grid>
|
HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
|
||||||
</Border>
|
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}">
|
||||||
</Panel>
|
<Panel>
|
||||||
</DataValidationErrors>
|
<TextBlock Name="PART_Watermark"
|
||||||
</ControlTemplate>
|
Text="{TemplateBinding Watermark}"
|
||||||
</Setter>
|
TextAlignment="{TemplateBinding TextAlignment}"
|
||||||
|
TextWrapping="{TemplateBinding TextWrapping}"
|
||||||
|
IsVisible="{TemplateBinding Text, Converter={x:Static StringConverters.IsNullOrEmpty}}"
|
||||||
|
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||||
|
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||||
|
IsHitTestVisible="False" />
|
||||||
|
<TextPresenter Name="PART_TextPresenter"
|
||||||
|
Text="{TemplateBinding Text, Mode=TwoWay}"
|
||||||
|
CaretIndex="{TemplateBinding CaretIndex}"
|
||||||
|
SelectionStart="{TemplateBinding SelectionStart}"
|
||||||
|
SelectionEnd="{TemplateBinding SelectionEnd}"
|
||||||
|
TextAlignment="{TemplateBinding TextAlignment}"
|
||||||
|
TextWrapping="{TemplateBinding TextWrapping}"
|
||||||
|
PasswordChar="{TemplateBinding PasswordChar}"
|
||||||
|
RevealPassword="{TemplateBinding RevealPassword}"
|
||||||
|
SelectionBrush="{TemplateBinding SelectionBrush}"
|
||||||
|
SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}"
|
||||||
|
CaretBrush="{TemplateBinding CaretBrush}"
|
||||||
|
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||||
|
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
|
||||||
|
</Panel>
|
||||||
|
</ScrollViewer>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1"
|
||||||
|
Grid.Column="2"
|
||||||
|
Name="PART_Suffix"
|
||||||
|
Text="{TemplateBinding attached:TextBoxAssist.SuffixText}"
|
||||||
|
IsVisible="{TemplateBinding attached:TextBoxAssist.SuffixText, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||||
|
IsHitTestVisible="False"
|
||||||
|
HorizontalAlignment="Right" />
|
||||||
|
</Grid>
|
||||||
|
<ContentPresenter Grid.Column="2" Content="{TemplateBinding InnerRightContent}" />
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</Panel>
|
||||||
|
</DataValidationErrors>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style Selector="TextBox /template/ TextBlock#PART_Prefix">
|
<Style Selector="TextBox /template/ TextBlock#PART_Prefix">
|
||||||
<Setter Property="Foreground" Value="{DynamicResource TextControlForegroundDisabled}"></Setter>
|
<Setter Property="Foreground" Value="{DynamicResource TextControlForegroundDisabled}"></Setter>
|
||||||
<Setter Property="Margin" Value="-4 0 4 0"></Setter>
|
<Setter Property="Margin" Value="-4 0 4 0"></Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
|||||||
72
src/Artemis.UI/Models/NodesClipboardModel.cs
Normal file
72
src/Artemis.UI/Models/NodesClipboardModel.cs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Storage.Entities.Profile.Nodes;
|
||||||
|
using FluentAvalonia.Core;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Models;
|
||||||
|
|
||||||
|
public class NodesClipboardModel
|
||||||
|
{
|
||||||
|
public NodesClipboardModel(NodeScript nodeScript, List<INode> nodes)
|
||||||
|
{
|
||||||
|
nodeScript.Save();
|
||||||
|
|
||||||
|
// Grab all entities belonging to provided nodes
|
||||||
|
Nodes = nodeScript.Entity.Nodes.Where(e => nodes.Any(n => n.Id == e.Id)).ToList();
|
||||||
|
// Grab all connections between provided nodes
|
||||||
|
Connections = nodeScript.Entity.Connections.Where(e => nodes.Any(n => n.Id == e.SourceNode) && nodes.Any(n => n.Id == e.TargetNode)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodesClipboardModel()
|
||||||
|
{
|
||||||
|
Nodes = new List<NodeEntity>();
|
||||||
|
Connections = new List<NodeConnectionEntity>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<NodeEntity> Nodes { get; set; }
|
||||||
|
public List<NodeConnectionEntity> Connections { get; set; }
|
||||||
|
|
||||||
|
public List<INode> Paste(NodeScript nodeScript, double x, double y)
|
||||||
|
{
|
||||||
|
if (!Nodes.Any())
|
||||||
|
return new List<INode>();
|
||||||
|
|
||||||
|
nodeScript.Save();
|
||||||
|
|
||||||
|
// Copy the entities, not messing with the originals
|
||||||
|
List<NodeEntity> nodes = Nodes.Select(n => new NodeEntity(n)).ToList();
|
||||||
|
List<NodeConnectionEntity> connections = Connections.Select(c => new NodeConnectionEntity(c)).ToList();
|
||||||
|
|
||||||
|
double xOffset = x - nodes.Min(n => n.X);
|
||||||
|
double yOffset = y - nodes.Min(n => n.Y);
|
||||||
|
|
||||||
|
foreach (NodeEntity node in nodes)
|
||||||
|
{
|
||||||
|
// Give each node a new GUID, updating any connections to it
|
||||||
|
Guid newGuid = Guid.NewGuid();
|
||||||
|
foreach (NodeConnectionEntity connection in connections)
|
||||||
|
{
|
||||||
|
if (connection.SourceNode == node.Id)
|
||||||
|
connection.SourceNode = newGuid;
|
||||||
|
else if (connection.TargetNode == node.Id)
|
||||||
|
connection.TargetNode = newGuid;
|
||||||
|
|
||||||
|
// Only add the connection if this is the first time we hit it
|
||||||
|
if (!nodeScript.Entity.Connections.Contains(connection))
|
||||||
|
nodeScript.Entity.Connections.Add(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.Id = newGuid;
|
||||||
|
node.X += xOffset;
|
||||||
|
node.Y += yOffset;
|
||||||
|
nodeScript.Entity.Nodes.Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeScript.Load();
|
||||||
|
|
||||||
|
// Return the newly created nodes
|
||||||
|
return nodeScript.Nodes.Where(n => nodes.Any(e => e.Id == n.Id)).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,7 +11,7 @@
|
|||||||
</UserControl.Styles>
|
</UserControl.Styles>
|
||||||
<Grid RowDefinitions="60,Auto,Auto,*,Auto,Auto">
|
<Grid RowDefinitions="60,Auto,Auto,*,Auto,Auto">
|
||||||
<Grid Grid.Row="0" IsHitTestVisible="False" ColumnDefinitions="Auto,*">
|
<Grid Grid.Row="0" IsHitTestVisible="False" ColumnDefinitions="Auto,*">
|
||||||
<Image Grid.Column="0" Margin="12" Source="/Assets/Images/Logo/bow.png" RenderOptions.BitmapInterpolationMode="HighQuality"/>
|
<Image Grid.Column="0" Margin="12" Source="/Assets/Images/Logo/bow.png" RenderOptions.BitmapInterpolationMode="HighQuality" />
|
||||||
<TextBlock Grid.Column="1"
|
<TextBlock Grid.Column="1"
|
||||||
FontSize="24"
|
FontSize="24"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
@ -46,6 +46,8 @@
|
|||||||
Width="44"
|
Width="44"
|
||||||
Height="44"
|
Height="44"
|
||||||
ToolTip.Tip="View website"
|
ToolTip.Tip="View website"
|
||||||
|
ToolTip.Placement="Top"
|
||||||
|
ToolTip.VerticalOffset="-5"
|
||||||
NavigateUri="https://artemis-rgb.com">
|
NavigateUri="https://artemis-rgb.com">
|
||||||
<avalonia:MaterialIcon Kind="Web" Width="20" Height="20" />
|
<avalonia:MaterialIcon Kind="Web" Width="20" Height="20" />
|
||||||
</controls:HyperlinkButton>
|
</controls:HyperlinkButton>
|
||||||
@ -53,6 +55,8 @@
|
|||||||
Width="44"
|
Width="44"
|
||||||
Height="44"
|
Height="44"
|
||||||
ToolTip.Tip="View GitHub repository"
|
ToolTip.Tip="View GitHub repository"
|
||||||
|
ToolTip.Placement="Top"
|
||||||
|
ToolTip.VerticalOffset="-5"
|
||||||
NavigateUri="https://github.com/Artemis-RGB/Artemis">
|
NavigateUri="https://github.com/Artemis-RGB/Artemis">
|
||||||
<avalonia:MaterialIcon Kind="Github" Width="20" Height="20" />
|
<avalonia:MaterialIcon Kind="Github" Width="20" Height="20" />
|
||||||
</controls:HyperlinkButton>
|
</controls:HyperlinkButton>
|
||||||
@ -60,6 +64,8 @@
|
|||||||
Width="44"
|
Width="44"
|
||||||
Height="44"
|
Height="44"
|
||||||
ToolTip.Tip="View Wiki"
|
ToolTip.Tip="View Wiki"
|
||||||
|
ToolTip.Placement="Top"
|
||||||
|
ToolTip.VerticalOffset="-5"
|
||||||
NavigateUri="https://wiki.artemis-rgb.com">
|
NavigateUri="https://wiki.artemis-rgb.com">
|
||||||
<avalonia:MaterialIcon Kind="BookOpenOutline" Width="20" Height="20" />
|
<avalonia:MaterialIcon Kind="BookOpenOutline" Width="20" Height="20" />
|
||||||
</controls:HyperlinkButton>
|
</controls:HyperlinkButton>
|
||||||
@ -67,6 +73,8 @@
|
|||||||
Width="44"
|
Width="44"
|
||||||
Height="44"
|
Height="44"
|
||||||
ToolTip.Tip="Join our Discord"
|
ToolTip.Tip="Join our Discord"
|
||||||
|
ToolTip.Placement="Top"
|
||||||
|
ToolTip.VerticalOffset="-5"
|
||||||
NavigateUri="https://discord.gg/S3MVaC9">
|
NavigateUri="https://discord.gg/S3MVaC9">
|
||||||
<avalonia:MaterialIcon Kind="Chat" Width="20" Height="20" />
|
<avalonia:MaterialIcon Kind="Chat" Width="20" Height="20" />
|
||||||
</controls:HyperlinkButton>
|
</controls:HyperlinkButton>
|
||||||
@ -74,6 +82,8 @@
|
|||||||
Width="44"
|
Width="44"
|
||||||
Height="44"
|
Height="44"
|
||||||
ToolTip.Tip="View donation options"
|
ToolTip.Tip="View donation options"
|
||||||
|
ToolTip.Placement="Top"
|
||||||
|
ToolTip.VerticalOffset="-5"
|
||||||
NavigateUri="https://wiki.artemis-rgb.com/en/donating">
|
NavigateUri="https://wiki.artemis-rgb.com/en/donating">
|
||||||
<avalonia:MaterialIcon Kind="Gift" Width="20" Height="20" />
|
<avalonia:MaterialIcon Kind="Gift" Width="20" Height="20" />
|
||||||
</controls:HyperlinkButton>
|
</controls:HyperlinkButton>
|
||||||
|
|||||||
@ -24,11 +24,6 @@
|
|||||||
Stroke="{CompiledBinding CableColor, Converter={StaticResource ColorToSolidColorBrushConverter}}"
|
Stroke="{CompiledBinding CableColor, Converter={StaticResource ColorToSolidColorBrushConverter}}"
|
||||||
StrokeThickness="4"
|
StrokeThickness="4"
|
||||||
StrokeLineCap="Round">
|
StrokeLineCap="Round">
|
||||||
<Path.Transitions>
|
|
||||||
<Transitions>
|
|
||||||
<ThicknessTransition Property="Margin" Duration="200"></ThicknessTransition>
|
|
||||||
</Transitions>
|
|
||||||
</Path.Transitions>
|
|
||||||
<Path.Data>
|
<Path.Data>
|
||||||
<PathGeometry>
|
<PathGeometry>
|
||||||
<PathGeometry.Figures>
|
<PathGeometry.Figures>
|
||||||
@ -47,8 +42,6 @@
|
|||||||
BorderThickness="2"
|
BorderThickness="2"
|
||||||
CornerRadius="3"
|
CornerRadius="3"
|
||||||
Padding="4"
|
Padding="4"
|
||||||
Canvas.Left="{CompiledBinding ValuePoint.X}"
|
|
||||||
Canvas.Top="{CompiledBinding ValuePoint.Y}"
|
|
||||||
IsVisible="{CompiledBinding DisplayValue}">
|
IsVisible="{CompiledBinding DisplayValue}">
|
||||||
<ContentControl Content="{CompiledBinding FromViewModel.Pin.PinValue}">
|
<ContentControl Content="{CompiledBinding FromViewModel.Pin.PinValue}">
|
||||||
<ContentControl.DataTemplates>
|
<ContentControl.DataTemplates>
|
||||||
|
|||||||
@ -8,6 +8,7 @@ using Avalonia.Input;
|
|||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
using Avalonia.Rendering;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.VisualScripting;
|
namespace Artemis.UI.Screens.VisualScripting;
|
||||||
@ -29,9 +30,9 @@ public class CableView : ReactiveUserControl<CableViewModel>
|
|||||||
{
|
{
|
||||||
_valueBorder.GetObservable(BoundsProperty).Subscribe(rect => _valueBorder.RenderTransform = new TranslateTransform(rect.Width / 2 * -1, rect.Height / 2 * -1)).DisposeWith(d);
|
_valueBorder.GetObservable(BoundsProperty).Subscribe(rect => _valueBorder.RenderTransform = new TranslateTransform(rect.Width / 2 * -1, rect.Height / 2 * -1)).DisposeWith(d);
|
||||||
|
|
||||||
ViewModel.WhenAnyValue(vm => vm.FromPoint).Subscribe(_ => Update()).DisposeWith(d);
|
ViewModel.WhenAnyValue(vm => vm.FromPoint).Subscribe(_ => Update(true)).DisposeWith(d);
|
||||||
ViewModel.WhenAnyValue(vm => vm.ToPoint).Subscribe(_ => Update()).DisposeWith(d);
|
ViewModel.WhenAnyValue(vm => vm.ToPoint).Subscribe(_ => Update(false)).DisposeWith(d);
|
||||||
Update();
|
Update(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,10 +41,12 @@ public class CableView : ReactiveUserControl<CableViewModel>
|
|||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Update()
|
private void Update(bool from)
|
||||||
{
|
{
|
||||||
// Workaround for https://github.com/AvaloniaUI/Avalonia/issues/4748
|
// Workaround for https://github.com/AvaloniaUI/Avalonia/issues/4748
|
||||||
_cablePath.Margin = _cablePath.Margin != new Thickness(0, 0, 0, 0) ? new Thickness(0, 0, 0, 0) : new Thickness(1, 1, 0, 0);
|
_cablePath.Margin = new Thickness(_cablePath.Margin.Left + 1, _cablePath.Margin.Top + 1, 0, 0);
|
||||||
|
if (_cablePath.Margin.Left > 2)
|
||||||
|
_cablePath.Margin = new Thickness(0, 0, 0, 0);
|
||||||
|
|
||||||
PathFigure pathFigure = ((PathGeometry) _cablePath.Data).Figures.First();
|
PathFigure pathFigure = ((PathGeometry) _cablePath.Data).Figures.First();
|
||||||
BezierSegment segment = (BezierSegment) pathFigure.Segments!.First();
|
BezierSegment segment = (BezierSegment) pathFigure.Segments!.First();
|
||||||
@ -51,6 +54,11 @@ public class CableView : ReactiveUserControl<CableViewModel>
|
|||||||
segment.Point1 = new Point(ViewModel.FromPoint.X + CABLE_OFFSET, ViewModel.FromPoint.Y);
|
segment.Point1 = new Point(ViewModel.FromPoint.X + CABLE_OFFSET, ViewModel.FromPoint.Y);
|
||||||
segment.Point2 = new Point(ViewModel.ToPoint.X - CABLE_OFFSET, ViewModel.ToPoint.Y);
|
segment.Point2 = new Point(ViewModel.ToPoint.X - CABLE_OFFSET, ViewModel.ToPoint.Y);
|
||||||
segment.Point3 = new Point(ViewModel.ToPoint.X, ViewModel.ToPoint.Y);
|
segment.Point3 = new Point(ViewModel.ToPoint.X, ViewModel.ToPoint.Y);
|
||||||
|
|
||||||
|
Canvas.SetLeft(_valueBorder, ViewModel.FromPoint.X + (ViewModel.ToPoint.X - ViewModel.FromPoint.X) / 2);
|
||||||
|
Canvas.SetTop(_valueBorder, ViewModel.FromPoint.Y + (ViewModel.ToPoint.Y - ViewModel.FromPoint.Y) / 2);
|
||||||
|
|
||||||
|
_cablePath.InvalidateVisual();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPointerEnter(object? sender, PointerEventArgs e)
|
private void OnPointerEnter(object? sender, PointerEventArgs e)
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
@ -27,7 +28,6 @@ public class CableViewModel : ActivatableViewModelBase
|
|||||||
private PinViewModel? _fromViewModel;
|
private PinViewModel? _fromViewModel;
|
||||||
private ObservableAsPropertyHelper<Point>? _toPoint;
|
private ObservableAsPropertyHelper<Point>? _toPoint;
|
||||||
private PinViewModel? _toViewModel;
|
private PinViewModel? _toViewModel;
|
||||||
private ObservableAsPropertyHelper<Point>? _valuePoint;
|
|
||||||
|
|
||||||
public CableViewModel(NodeScriptViewModel nodeScriptViewModel, IPin from, IPin to, ISettingsService settingsService)
|
public CableViewModel(NodeScriptViewModel nodeScriptViewModel, IPin from, IPin to, ISettingsService settingsService)
|
||||||
{
|
{
|
||||||
@ -63,11 +63,6 @@ public class CableViewModel : ActivatableViewModelBase
|
|||||||
.Switch()
|
.Switch()
|
||||||
.ToProperty(this, vm => vm.ToPoint)
|
.ToProperty(this, vm => vm.ToPoint)
|
||||||
.DisposeWith(d);
|
.DisposeWith(d);
|
||||||
_valuePoint = this.WhenAnyValue(vm => vm.FromPoint, vm => vm.ToPoint).Select(tuple => new Point(
|
|
||||||
tuple.Item1.X + (tuple.Item2.X - tuple.Item1.X) / 2,
|
|
||||||
tuple.Item1.Y + (tuple.Item2.Y - tuple.Item1.Y) / 2
|
|
||||||
)).ToProperty(this, vm => vm.ValuePoint)
|
|
||||||
.DisposeWith(d);
|
|
||||||
|
|
||||||
// Not a perfect solution but this makes sure the cable never renders at 0,0 (can happen when the cable spawns before the pin ever rendered)
|
// Not a perfect solution but this makes sure the cable never renders at 0,0 (can happen when the cable spawns before the pin ever rendered)
|
||||||
_connected = this.WhenAnyValue(vm => vm.FromPoint, vm => vm.ToPoint)
|
_connected = this.WhenAnyValue(vm => vm.FromPoint, vm => vm.ToPoint)
|
||||||
@ -104,11 +99,10 @@ public class CableViewModel : ActivatableViewModelBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
public bool Connected => _connected?.Value ?? false;
|
public bool Connected => _connected?.Value ?? false;
|
||||||
public bool IsFirst => _from.ConnectedTo[0] == _to;
|
public bool IsFirst => _from.ConnectedTo.FirstOrDefault() == _to;
|
||||||
|
|
||||||
public Point FromPoint => _fromPoint?.Value ?? new Point();
|
public Point FromPoint => _fromPoint?.Value ?? new Point();
|
||||||
public Point ToPoint => _toPoint?.Value ?? new Point();
|
public Point ToPoint => _toPoint?.Value ?? new Point();
|
||||||
public Point ValuePoint => _valuePoint?.Value ?? new Point();
|
|
||||||
public Color CableColor => _cableColor?.Value ?? new Color(255, 255, 255, 255);
|
public Color CableColor => _cableColor?.Value ?? new Color(255, 255, 255, 255);
|
||||||
|
|
||||||
public void UpdateDisplayValue(bool hoveringOver)
|
public void UpdateDisplayValue(bool hoveringOver)
|
||||||
|
|||||||
@ -30,6 +30,8 @@
|
|||||||
<KeyBinding Command="{CompiledBinding ClearSelection}" Gesture="Escape" />
|
<KeyBinding Command="{CompiledBinding ClearSelection}" Gesture="Escape" />
|
||||||
<KeyBinding Command="{CompiledBinding DeleteSelected}" Gesture="Delete" />
|
<KeyBinding Command="{CompiledBinding DeleteSelected}" Gesture="Delete" />
|
||||||
<KeyBinding Command="{CompiledBinding DuplicateSelected}" Gesture="Ctrl+D" />
|
<KeyBinding Command="{CompiledBinding DuplicateSelected}" Gesture="Ctrl+D" />
|
||||||
|
<KeyBinding Command="{CompiledBinding CopySelected}" Gesture="Ctrl+C" />
|
||||||
|
<KeyBinding Command="{CompiledBinding PasteSelected}" Gesture="Ctrl+V" />
|
||||||
<KeyBinding Command="{CompiledBinding History.Undo}" Gesture="Ctrl+Z" />
|
<KeyBinding Command="{CompiledBinding History.Undo}" Gesture="Ctrl+Z" />
|
||||||
<KeyBinding Command="{CompiledBinding History.Redo}" Gesture="Ctrl+Y" />
|
<KeyBinding Command="{CompiledBinding History.Redo}" Gesture="Ctrl+Y" />
|
||||||
</UserControl.KeyBindings>
|
</UserControl.KeyBindings>
|
||||||
|
|||||||
@ -14,6 +14,7 @@ using Avalonia.Markup.Xaml;
|
|||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
using Avalonia.VisualTree;
|
||||||
using DynamicData.Binding;
|
using DynamicData.Binding;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
@ -39,6 +40,8 @@ public class NodeScriptView : ReactiveUserControl<NodeScriptViewModel>
|
|||||||
|
|
||||||
_zoomBorder.AddHandler(PointerReleasedEvent, CanvasOnPointerReleased, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble, true);
|
_zoomBorder.AddHandler(PointerReleasedEvent, CanvasOnPointerReleased, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble, true);
|
||||||
_zoomBorder.AddHandler(PointerWheelChangedEvent, ZoomOnPointerWheelChanged, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble, true);
|
_zoomBorder.AddHandler(PointerWheelChangedEvent, ZoomOnPointerWheelChanged, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble, true);
|
||||||
|
_zoomBorder.AddHandler(PointerMovedEvent, ZoomOnPointerMoved, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble, true);
|
||||||
|
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
ViewModel!.AutoFitRequested += ViewModelOnAutoFitRequested;
|
ViewModel!.AutoFitRequested += ViewModelOnAutoFitRequested;
|
||||||
@ -67,6 +70,12 @@ public class NodeScriptView : ReactiveUserControl<NodeScriptViewModel>
|
|||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ZoomOnPointerMoved(object? sender, PointerEventArgs e)
|
||||||
|
{
|
||||||
|
if (ViewModel != null)
|
||||||
|
ViewModel.PastePosition = e.GetPosition(_grid);
|
||||||
|
}
|
||||||
|
|
||||||
private void ShowPickerAt(Point point)
|
private void ShowPickerAt(Point point)
|
||||||
{
|
{
|
||||||
if (ViewModel == null)
|
if (ViewModel == null)
|
||||||
|
|||||||
@ -6,9 +6,12 @@ using System.Linq;
|
|||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Reactive.Subjects;
|
using System.Reactive.Subjects;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Events;
|
using Artemis.Core.Events;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.Models;
|
||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
using Artemis.UI.Screens.VisualScripting.Pins;
|
using Artemis.UI.Screens.VisualScripting.Pins;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
@ -16,6 +19,7 @@ using Artemis.UI.Shared.Services.NodeEditor;
|
|||||||
using Artemis.UI.Shared.Services.NodeEditor.Commands;
|
using Artemis.UI.Shared.Services.NodeEditor.Commands;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls.Mixins;
|
using Avalonia.Controls.Mixins;
|
||||||
|
using Avalonia.Input;
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
using DynamicData.Binding;
|
using DynamicData.Binding;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
@ -24,6 +28,8 @@ namespace Artemis.UI.Screens.VisualScripting;
|
|||||||
|
|
||||||
public class NodeScriptViewModel : ActivatableViewModelBase
|
public class NodeScriptViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
|
public const string CLIPBOARD_DATA_FORMAT = "Artemis.Nodes";
|
||||||
|
|
||||||
private readonly INodeEditorService _nodeEditorService;
|
private readonly INodeEditorService _nodeEditorService;
|
||||||
private readonly INodeService _nodeService;
|
private readonly INodeService _nodeService;
|
||||||
private readonly SourceList<NodeViewModel> _nodeViewModels;
|
private readonly SourceList<NodeViewModel> _nodeViewModels;
|
||||||
@ -33,6 +39,7 @@ public class NodeScriptViewModel : ActivatableViewModelBase
|
|||||||
private DragCableViewModel? _dragViewModel;
|
private DragCableViewModel? _dragViewModel;
|
||||||
private List<NodeViewModel>? _initialNodeSelection;
|
private List<NodeViewModel>? _initialNodeSelection;
|
||||||
private Matrix _panMatrix;
|
private Matrix _panMatrix;
|
||||||
|
private Point _pastePosition;
|
||||||
|
|
||||||
public NodeScriptViewModel(NodeScript nodeScript, bool isPreview, INodeVmFactory nodeVmFactory, INodeService nodeService, INodeEditorService nodeEditorService)
|
public NodeScriptViewModel(NodeScript nodeScript, bool isPreview, INodeVmFactory nodeVmFactory, INodeService nodeService, INodeEditorService nodeEditorService)
|
||||||
{
|
{
|
||||||
@ -86,8 +93,8 @@ public class NodeScriptViewModel : ActivatableViewModelBase
|
|||||||
ClearSelection = ReactiveCommand.Create(ExecuteClearSelection);
|
ClearSelection = ReactiveCommand.Create(ExecuteClearSelection);
|
||||||
DeleteSelected = ReactiveCommand.Create(ExecuteDeleteSelected);
|
DeleteSelected = ReactiveCommand.Create(ExecuteDeleteSelected);
|
||||||
DuplicateSelected = ReactiveCommand.Create(ExecuteDuplicateSelected);
|
DuplicateSelected = ReactiveCommand.Create(ExecuteDuplicateSelected);
|
||||||
CopySelected = ReactiveCommand.Create(ExecuteCopySelected);
|
CopySelected = ReactiveCommand.CreateFromTask(ExecuteCopySelected);
|
||||||
PasteSelected = ReactiveCommand.Create(ExecutePasteSelected);
|
PasteSelected = ReactiveCommand.CreateFromTask(ExecutePasteSelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
public NodeScript NodeScript { get; }
|
public NodeScript NodeScript { get; }
|
||||||
@ -118,6 +125,12 @@ public class NodeScriptViewModel : ActivatableViewModelBase
|
|||||||
set => RaiseAndSetIfChanged(ref _panMatrix, value);
|
set => RaiseAndSetIfChanged(ref _panMatrix, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Point PastePosition
|
||||||
|
{
|
||||||
|
get => _pastePosition;
|
||||||
|
set => RaiseAndSetIfChanged(ref _pastePosition, value);
|
||||||
|
}
|
||||||
|
|
||||||
public void DeleteSelectedNodes()
|
public void DeleteSelectedNodes()
|
||||||
{
|
{
|
||||||
List<NodeViewModel> toRemove = NodeViewModels.Where(vm => vm.IsSelected && !vm.Node.IsDefaultNode && !vm.Node.IsExitNode).ToList();
|
List<NodeViewModel> toRemove = NodeViewModels.Where(vm => vm.IsSelected && !vm.Node.IsDefaultNode && !vm.Node.IsExitNode).ToList();
|
||||||
@ -279,11 +292,39 @@ public class NodeScriptViewModel : ActivatableViewModelBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExecuteCopySelected()
|
private async Task ExecuteCopySelected()
|
||||||
{
|
{
|
||||||
|
if (Application.Current?.Clipboard == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
List<INode> nodes = NodeViewModels.Where(vm => vm.IsSelected).Select(vm => vm.Node).Where(n => !n.IsDefaultNode && !n.IsExitNode).ToList();
|
||||||
|
DataObject dataObject = new();
|
||||||
|
string copy = CoreJson.SerializeObject(new NodesClipboardModel(NodeScript, nodes), true);
|
||||||
|
dataObject.Set(CLIPBOARD_DATA_FORMAT, copy);
|
||||||
|
await Application.Current.Clipboard.SetDataObjectAsync(dataObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExecutePasteSelected()
|
private async Task ExecutePasteSelected()
|
||||||
{
|
{
|
||||||
|
if (Application.Current?.Clipboard == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
byte[]? bytes = (byte[]?) await Application.Current.Clipboard.GetDataAsync(CLIPBOARD_DATA_FORMAT);
|
||||||
|
if (bytes == null!)
|
||||||
|
return;
|
||||||
|
|
||||||
|
NodesClipboardModel? nodesClipboardModel = CoreJson.DeserializeObject<NodesClipboardModel>(Encoding.Unicode.GetString(bytes), true);
|
||||||
|
if (nodesClipboardModel == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
List<INode> nodes = nodesClipboardModel.Paste(NodeScript, PastePosition.X, PastePosition.Y);
|
||||||
|
|
||||||
|
using NodeEditorCommandScope scope = _nodeEditorService.CreateCommandScope(NodeScript, "Paste nodes");
|
||||||
|
foreach (INode node in nodes)
|
||||||
|
_nodeEditorService.ExecuteCommand(NodeScript, new AddNode(NodeScript, node));
|
||||||
|
|
||||||
|
// Select only the new nodes
|
||||||
|
foreach (NodeViewModel nodeViewModel in NodeViewModels)
|
||||||
|
nodeViewModel.IsSelected = nodes.Contains(nodeViewModel.Node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,6 +4,7 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
xmlns:visualScripting="clr-namespace:Artemis.UI.Screens.VisualScripting"
|
xmlns:visualScripting="clr-namespace:Artemis.UI.Screens.VisualScripting"
|
||||||
|
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
mc:Ignorable="d" d:DesignWidth="250" d:DesignHeight="150"
|
mc:Ignorable="d" d:DesignWidth="250" d:DesignHeight="150"
|
||||||
x:Class="Artemis.UI.Screens.VisualScripting.NodeView"
|
x:Class="Artemis.UI.Screens.VisualScripting.NodeView"
|
||||||
x:DataType="visualScripting:NodeViewModel">
|
x:DataType="visualScripting:NodeViewModel">
|
||||||
@ -37,7 +38,7 @@
|
|||||||
ClipToBounds="True"
|
ClipToBounds="True"
|
||||||
Background="{DynamicResource ContentDialogBackground}">
|
Background="{DynamicResource ContentDialogBackground}">
|
||||||
<Border Background="{DynamicResource TaskDialogHeaderBackground}">
|
<Border Background="{DynamicResource TaskDialogHeaderBackground}">
|
||||||
<Grid Classes="node-header" VerticalAlignment="Top" ColumnDefinitions="Auto,*,Auto">
|
<Grid Classes="node-header" VerticalAlignment="Top" ColumnDefinitions="Auto,*,Auto,Auto">
|
||||||
<Button Grid.Column="0"
|
<Button Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
IsVisible="{CompiledBinding Node.BrokenState, Converter={x:Static ObjectConverters.IsNotNull}}"
|
IsVisible="{CompiledBinding Node.BrokenState, Converter={x:Static ObjectConverters.IsNotNull}}"
|
||||||
@ -53,7 +54,17 @@
|
|||||||
|
|
||||||
<TextBlock Grid.Column="1" VerticalAlignment="Center" Margin="10 0 0 0" Text="{CompiledBinding Node.Name}" ToolTip.Tip="{CompiledBinding Node.Description}" />
|
<TextBlock Grid.Column="1" VerticalAlignment="Center" Margin="10 0 0 0" Text="{CompiledBinding Node.Name}" ToolTip.Tip="{CompiledBinding Node.Description}" />
|
||||||
|
|
||||||
<Button Grid.Column="2" VerticalAlignment="Center" Classes="icon-button icon-button-small" Margin="5" Command="{CompiledBinding DeleteNode}">
|
|
||||||
|
<controls:HyperlinkButton Grid.Column="2"
|
||||||
|
IsVisible="{CompiledBinding Node.HelpUrl, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Classes="icon-button icon-button-small"
|
||||||
|
Margin="5 5 -3 5"
|
||||||
|
ToolTip.Tip="View node help"
|
||||||
|
NavigateUri="{CompiledBinding Node.HelpUrl}">
|
||||||
|
<avalonia:MaterialIcon Kind="Help" />
|
||||||
|
</controls:HyperlinkButton>
|
||||||
|
<Button Grid.Column="3" VerticalAlignment="Center" Classes="icon-button icon-button-small" Margin="5" Command="{CompiledBinding DeleteNode}">
|
||||||
<avalonia:MaterialIcon Kind="Close"></avalonia:MaterialIcon>
|
<avalonia:MaterialIcon Kind="Close"></avalonia:MaterialIcon>
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace Artemis.VisualScripting.Nodes.Branching;
|
|||||||
[Node("Branch", "Forwards one of two values depending on an input boolean", "Branching", InputType = typeof(object), OutputType = typeof(object))]
|
[Node("Branch", "Forwards one of two values depending on an input boolean", "Branching", InputType = typeof(object), OutputType = typeof(object))]
|
||||||
public class BooleanBranchNode : Node
|
public class BooleanBranchNode : Node
|
||||||
{
|
{
|
||||||
public BooleanBranchNode() : base("Branch", "Forwards one of two values depending on an input boolean")
|
public BooleanBranchNode()
|
||||||
{
|
{
|
||||||
BooleanInput = CreateInputPin<bool>();
|
BooleanInput = CreateInputPin<bool>();
|
||||||
TrueInput = CreateInputPin(typeof(object), "True");
|
TrueInput = CreateInputPin(typeof(object), "True");
|
||||||
|
|||||||
@ -9,7 +9,7 @@ public class EnumSwitchNode : Node
|
|||||||
{
|
{
|
||||||
private readonly Dictionary<Enum, InputPin> _inputPins;
|
private readonly Dictionary<Enum, InputPin> _inputPins;
|
||||||
|
|
||||||
public EnumSwitchNode() : base("Enum Branch", "desc")
|
public EnumSwitchNode()
|
||||||
{
|
{
|
||||||
_inputPins = new Dictionary<Enum, InputPin>();
|
_inputPins = new Dictionary<Enum, InputPin>();
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace Artemis.VisualScripting.Nodes.Color;
|
|||||||
[Node("Brighten Color", "Brightens a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
[Node("Brighten Color", "Brightens a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||||
public class BrightenSKColorNode : Node
|
public class BrightenSKColorNode : Node
|
||||||
{
|
{
|
||||||
public BrightenSKColorNode() : base("Brighten Color", "Brightens a color by a specified amount in percent")
|
public BrightenSKColorNode()
|
||||||
{
|
{
|
||||||
Input = CreateInputPin<SKColor>("Color");
|
Input = CreateInputPin<SKColor>("Color");
|
||||||
Percentage = CreateInputPin<Numeric>("%");
|
Percentage = CreateInputPin<Numeric>("%");
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public class ColorGradientFromPinsNode : Node
|
|||||||
public InputPinCollection<SKColor> Colors { get; set; }
|
public InputPinCollection<SKColor> Colors { get; set; }
|
||||||
public InputPinCollection<Numeric> Positions { get; set; }
|
public InputPinCollection<Numeric> Positions { get; set; }
|
||||||
|
|
||||||
public ColorGradientFromPinsNode() : base("Color Gradient", "Outputs a Color Gradient from colors and positions")
|
public ColorGradientFromPinsNode()
|
||||||
{
|
{
|
||||||
Colors = CreateInputPinCollection<SKColor>("Colors", 0);
|
Colors = CreateInputPinCollection<SKColor>("Colors", 0);
|
||||||
Positions = CreateInputPinCollection<Numeric>("Positions", 0);
|
Positions = CreateInputPinCollection<Numeric>("Positions", 0);
|
||||||
|
|||||||
@ -10,7 +10,7 @@ public class ColorGradientNode : Node<ColorGradient, ColorGradientNodeCustomView
|
|||||||
{
|
{
|
||||||
private readonly List<InputPin> _inputPins;
|
private readonly List<InputPin> _inputPins;
|
||||||
|
|
||||||
public ColorGradientNode() : base("Color Gradient", "Outputs a color gradient with the given colors")
|
public ColorGradientNode()
|
||||||
{
|
{
|
||||||
_inputPins = new List<InputPin>();
|
_inputPins = new List<InputPin>();
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace Artemis.VisualScripting.Nodes.Color;
|
|||||||
[Node("Darken Color", "Darkens a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
[Node("Darken Color", "Darkens a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||||
public class DarkenSKColorNode : Node
|
public class DarkenSKColorNode : Node
|
||||||
{
|
{
|
||||||
public DarkenSKColorNode() : base("Darken Color", "Darkens a color by a specified amount in percent")
|
public DarkenSKColorNode()
|
||||||
{
|
{
|
||||||
Input = CreateInputPin<SKColor>("Color");
|
Input = CreateInputPin<SKColor>("Color");
|
||||||
Percentage = CreateInputPin<Numeric>("%");
|
Percentage = CreateInputPin<Numeric>("%");
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace Artemis.VisualScripting.Nodes.Color;
|
|||||||
[Node("Desaturate Color", "Desaturates a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
[Node("Desaturate Color", "Desaturates a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||||
public class DesaturateSKColorNode : Node
|
public class DesaturateSKColorNode : Node
|
||||||
{
|
{
|
||||||
public DesaturateSKColorNode() : base("Desaturate Color", "Desaturates a color by a specified amount in percent")
|
public DesaturateSKColorNode()
|
||||||
{
|
{
|
||||||
Input = CreateInputPin<SKColor>("Color");
|
Input = CreateInputPin<SKColor>("Color");
|
||||||
Percentage = CreateInputPin<Numeric>("%");
|
Percentage = CreateInputPin<Numeric>("%");
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace Artemis.VisualScripting.Nodes.Color;
|
|||||||
[Node("HSL Color", "Creates a color from hue, saturation and lightness values", "Color", InputType = typeof(Numeric), OutputType = typeof(SKColor))]
|
[Node("HSL Color", "Creates a color from hue, saturation and lightness values", "Color", InputType = typeof(Numeric), OutputType = typeof(SKColor))]
|
||||||
public class HslSKColorNode : Node
|
public class HslSKColorNode : Node
|
||||||
{
|
{
|
||||||
public HslSKColorNode() : base("HSL Color", "Creates a color from hue, saturation and lightness values")
|
public HslSKColorNode()
|
||||||
{
|
{
|
||||||
H = CreateInputPin<Numeric>("H");
|
H = CreateInputPin<Numeric>("H");
|
||||||
S = CreateInputPin<Numeric>("S");
|
S = CreateInputPin<Numeric>("S");
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace Artemis.VisualScripting.Nodes.Color;
|
|||||||
[Node("Invert Color", "Inverts a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
[Node("Invert Color", "Inverts a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||||
public class InvertSKColorNode : Node
|
public class InvertSKColorNode : Node
|
||||||
{
|
{
|
||||||
public InvertSKColorNode() : base("Invert Color", "Inverts a color")
|
public InvertSKColorNode()
|
||||||
{
|
{
|
||||||
Input = CreateInputPin<SKColor>();
|
Input = CreateInputPin<SKColor>();
|
||||||
Output = CreateOutputPin<SKColor>();
|
Output = CreateOutputPin<SKColor>();
|
||||||
|
|||||||
@ -20,8 +20,8 @@ public class LerpSKColorNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public LerpSKColorNode()
|
public LerpSKColorNode()
|
||||||
: base("Lerp", "Interpolates linear between the two values A and B")
|
|
||||||
{
|
{
|
||||||
|
Name = "Lerp";
|
||||||
A = CreateInputPin<SKColor>("A");
|
A = CreateInputPin<SKColor>("A");
|
||||||
B = CreateInputPin<SKColor>("B");
|
B = CreateInputPin<SKColor>("B");
|
||||||
T = CreateInputPin<Numeric>("T");
|
T = CreateInputPin<Numeric>("T");
|
||||||
|
|||||||
@ -10,7 +10,6 @@ public class RampSKColorNode : Node<ColorGradient, RampSKColorNodeCustomViewMode
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public RampSKColorNode()
|
public RampSKColorNode()
|
||||||
: base("Color Ramp", "Maps values to colors with the use of a gradient.")
|
|
||||||
{
|
{
|
||||||
Input = CreateInputPin<Numeric>();
|
Input = CreateInputPin<Numeric>();
|
||||||
Output = CreateOutputPin<SKColor>();
|
Output = CreateOutputPin<SKColor>();
|
||||||
|
|||||||
@ -18,7 +18,6 @@ public class RgbSKColorNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public RgbSKColorNode()
|
public RgbSKColorNode()
|
||||||
: base("RGB Color", "Creates a color from red, green and blue values")
|
|
||||||
{
|
{
|
||||||
R = CreateInputPin<Numeric>("R");
|
R = CreateInputPin<Numeric>("R");
|
||||||
G = CreateInputPin<Numeric>("G");
|
G = CreateInputPin<Numeric>("G");
|
||||||
|
|||||||
@ -6,7 +6,7 @@ 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))]
|
[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 class RotateHueSKColorNode : Node
|
||||||
{
|
{
|
||||||
public RotateHueSKColorNode() : base("Rotate Color Hue", "Rotates the hue of a color by a specified amount in degrees")
|
public RotateHueSKColorNode()
|
||||||
{
|
{
|
||||||
Input = CreateInputPin<SKColor>("Color");
|
Input = CreateInputPin<SKColor>("Color");
|
||||||
Amount = CreateInputPin<Numeric>("Amount");
|
Amount = CreateInputPin<Numeric>("Amount");
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace Artemis.VisualScripting.Nodes.Color;
|
|||||||
[Node("Saturate Color", "Saturates a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
[Node("Saturate Color", "Saturates a color by a specified amount in percent", "Color", InputType = typeof(SKColor), OutputType = typeof(SKColor))]
|
||||||
public class SaturateSKColorNode : Node
|
public class SaturateSKColorNode : Node
|
||||||
{
|
{
|
||||||
public SaturateSKColorNode() : base("Saturate Color", "Saturates a color by a specified amount in percent")
|
public SaturateSKColorNode()
|
||||||
{
|
{
|
||||||
Input = CreateInputPin<SKColor>("Color");
|
Input = CreateInputPin<SKColor>("Color");
|
||||||
Percentage = CreateInputPin<Numeric>("%");
|
Percentage = CreateInputPin<Numeric>("%");
|
||||||
|
|||||||
@ -9,8 +9,8 @@ public class SumSKColorsNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public SumSKColorsNode()
|
public SumSKColorsNode()
|
||||||
: base("Sum", "Sums the connected color values.")
|
|
||||||
{
|
{
|
||||||
|
Name = "Sum";
|
||||||
Values = CreateInputPinCollection<SKColor>("Values", 2);
|
Values = CreateInputPinCollection<SKColor>("Values", 2);
|
||||||
Sum = CreateOutputPin<SKColor>("Sum");
|
Sum = CreateOutputPin<SKColor>("Sum");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,6 @@ public class ConvertToNumericNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public ConvertToNumericNode()
|
public ConvertToNumericNode()
|
||||||
: base("To Numeric", "Converts the input to a numeric.")
|
|
||||||
{
|
{
|
||||||
Input = CreateInputPin<object>();
|
Input = CreateInputPin<object>();
|
||||||
Output = CreateOutputPin<Numeric>();
|
Output = CreateOutputPin<Numeric>();
|
||||||
|
|||||||
@ -2,13 +2,12 @@
|
|||||||
|
|
||||||
namespace Artemis.VisualScripting.Nodes.Conversion;
|
namespace Artemis.VisualScripting.Nodes.Conversion;
|
||||||
|
|
||||||
[Node("To String", "Converts the input to a string.", "Conversion", InputType = typeof(object), OutputType = typeof(string))]
|
[Node("To Text", "Converts the input to text.", "Conversion", InputType = typeof(object), OutputType = typeof(string))]
|
||||||
public class ConvertToStringNode : Node
|
public class ConvertToStringNode : Node
|
||||||
{
|
{
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public ConvertToStringNode()
|
public ConvertToStringNode()
|
||||||
: base("To String", "Converts the input to a string.")
|
|
||||||
{
|
{
|
||||||
Input = CreateInputPin<object>();
|
Input = CreateInputPin<object>();
|
||||||
String = CreateOutputPin<string>();
|
String = CreateOutputPin<string>();
|
||||||
|
|||||||
@ -15,7 +15,7 @@ public class DataModelEventCycleNode : Node<DataModelPathEntity, DataModelEventC
|
|||||||
private DateTime _lastTrigger;
|
private DateTime _lastTrigger;
|
||||||
private bool _updating;
|
private bool _updating;
|
||||||
|
|
||||||
public DataModelEventCycleNode() : base("Data Model-Event Value Cycle", "Cycles through provided values each time the select event fires.")
|
public DataModelEventCycleNode()
|
||||||
{
|
{
|
||||||
_currentType = typeof(object);
|
_currentType = typeof(object);
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@ public class DataModelEventNode : Node<DataModelPathEntity, DataModelEventNodeCu
|
|||||||
private OutputPin? _oldValuePin;
|
private OutputPin? _oldValuePin;
|
||||||
private int _valueChangeCount;
|
private int _valueChangeCount;
|
||||||
|
|
||||||
public DataModelEventNode() : base("Data Model-Event", "Outputs the latest values of a data model event.")
|
public DataModelEventNode()
|
||||||
{
|
{
|
||||||
_objectOutputPins = new ObjectOutputPins(this);
|
_objectOutputPins = new ObjectOutputPins(this);
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ public class DataModelNode : Node<DataModelPathEntity, DataModelNodeCustomViewMo
|
|||||||
{
|
{
|
||||||
private DataModelPath? _dataModelPath;
|
private DataModelPath? _dataModelPath;
|
||||||
|
|
||||||
public DataModelNode() : base("Data Model", "Outputs a selectable data model value")
|
public DataModelNode()
|
||||||
{
|
{
|
||||||
Output = CreateOutputPin(typeof(object));
|
Output = CreateOutputPin(typeof(object));
|
||||||
StorageModified += (_, _) => UpdateDataModelPath();
|
StorageModified += (_, _) => UpdateDataModelPath();
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace Artemis.VisualScripting.Nodes.Easing;
|
|||||||
[Node("Easing Type", "Outputs a selectable easing type.", "Easing", OutputType = typeof(Easings.Functions))]
|
[Node("Easing Type", "Outputs a selectable easing type.", "Easing", OutputType = typeof(Easings.Functions))]
|
||||||
public class EasingTypeNode : Node<Easings.Functions, EasingTypeNodeCustomViewModel>
|
public class EasingTypeNode : Node<Easings.Functions, EasingTypeNodeCustomViewModel>
|
||||||
{
|
{
|
||||||
public EasingTypeNode() : base("Easing Type", "Outputs a selectable easing type.")
|
public EasingTypeNode()
|
||||||
{
|
{
|
||||||
Output = CreateOutputPin<Easings.Functions>();
|
Output = CreateOutputPin<Easings.Functions>();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public class NumericEasingNode : Node
|
|||||||
private float _sourceValue;
|
private float _sourceValue;
|
||||||
private float _targetValue;
|
private float _targetValue;
|
||||||
|
|
||||||
public NumericEasingNode() : base("Numeric Easing", "Outputs an eased numeric value")
|
public NumericEasingNode()
|
||||||
{
|
{
|
||||||
Input = CreateInputPin<Numeric>();
|
Input = CreateInputPin<Numeric>();
|
||||||
EasingTime = CreateInputPin<Numeric>("delay");
|
EasingTime = CreateInputPin<Numeric>("delay");
|
||||||
|
|||||||
@ -12,7 +12,7 @@ public class SKColorEasingNode : Node
|
|||||||
private SKColor _sourceValue;
|
private SKColor _sourceValue;
|
||||||
private SKColor _targetValue;
|
private SKColor _targetValue;
|
||||||
|
|
||||||
public SKColorEasingNode() : base("Color Easing", "Outputs an eased color value")
|
public SKColorEasingNode()
|
||||||
{
|
{
|
||||||
Input = CreateInputPin<SKColor>();
|
Input = CreateInputPin<SKColor>();
|
||||||
EasingTime = CreateInputPin<Numeric>("delay");
|
EasingTime = CreateInputPin<Numeric>("delay");
|
||||||
|
|||||||
@ -7,7 +7,7 @@ namespace Artemis.VisualScripting.Nodes.List;
|
|||||||
[Node("List Operator (Simple)", "Checks if any/all/no values in the input list match the input value", "List", InputType = typeof(IEnumerable), OutputType = typeof(bool))]
|
[Node("List Operator (Simple)", "Checks if any/all/no values in the input list match the input value", "List", InputType = typeof(IEnumerable), OutputType = typeof(bool))]
|
||||||
public class ListOperatorNode : Node<ListOperator, ListOperatorNodeCustomViewModel>
|
public class ListOperatorNode : Node<ListOperator, ListOperatorNodeCustomViewModel>
|
||||||
{
|
{
|
||||||
public ListOperatorNode() : base("List Operator (Simple)", "Checks if any/all/no values in the input list match the input value")
|
public ListOperatorNode()
|
||||||
{
|
{
|
||||||
InputList = CreateInputPin<IList>();
|
InputList = CreateInputPin<IList>();
|
||||||
InputValue = CreateInputPin<object>();
|
InputValue = CreateInputPin<object>();
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public class ListOperatorPredicateNode : Node<ListOperatorEntity, ListOperatorPr
|
|||||||
private readonly object _scriptLock = new();
|
private readonly object _scriptLock = new();
|
||||||
private ListOperatorPredicateStartNode _startNode;
|
private ListOperatorPredicateStartNode _startNode;
|
||||||
|
|
||||||
public ListOperatorPredicateNode() : base("List Operator (Advanced)", "Checks if any/all/no values in the input list match a condition")
|
public ListOperatorPredicateNode()
|
||||||
{
|
{
|
||||||
_startNode = new ListOperatorPredicateStartNode {X = -200};
|
_startNode = new ListOperatorPredicateStartNode {X = -200};
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,6 @@ public class ClampNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public ClampNode()
|
public ClampNode()
|
||||||
: base("Clamp", "Clamps the value to be in between min and max")
|
|
||||||
{
|
{
|
||||||
Value = CreateInputPin<Numeric>("Value");
|
Value = CreateInputPin<Numeric>("Value");
|
||||||
Min = CreateInputPin<Numeric>("Min");
|
Min = CreateInputPin<Numeric>("Min");
|
||||||
|
|||||||
@ -9,7 +9,6 @@ public class CounterNode : Node
|
|||||||
private float _progress;
|
private float _progress;
|
||||||
|
|
||||||
public CounterNode()
|
public CounterNode()
|
||||||
: base("Counter", "Counts from 0.0 to 1.0 at a configurable rate.")
|
|
||||||
{
|
{
|
||||||
Time = CreateInputPin<Numeric>("Time (ms)");
|
Time = CreateInputPin<Numeric>("Time (ms)");
|
||||||
Output = CreateOutputPin<Numeric>();
|
Output = CreateOutputPin<Numeric>();
|
||||||
|
|||||||
@ -19,7 +19,6 @@ public class LerpNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public LerpNode()
|
public LerpNode()
|
||||||
: base("Lerp", "Interpolates linear between the two values A and B")
|
|
||||||
{
|
{
|
||||||
A = CreateInputPin<Numeric>("A");
|
A = CreateInputPin<Numeric>("A");
|
||||||
B = CreateInputPin<Numeric>("B");
|
B = CreateInputPin<Numeric>("B");
|
||||||
|
|||||||
@ -5,7 +5,7 @@ using NoStringEvaluating.Models.FormulaChecker;
|
|||||||
|
|
||||||
namespace Artemis.VisualScripting.Nodes.Mathematics;
|
namespace Artemis.VisualScripting.Nodes.Mathematics;
|
||||||
|
|
||||||
[Node("Math Expression", "Outputs the result of a math expression.", "Mathematics", InputType = typeof(Numeric), OutputType = typeof(Numeric))]
|
[Node("Math Expression", "Outputs the result of a math expression.", "Mathematics", "https://wiki.artemis-rgb.com/en/guides/user/profiles/nodes/mathematics/math-expression", InputType = typeof(Numeric), OutputType = typeof(Numeric))]
|
||||||
public class MathExpressionNode : Node<string, MathExpressionNodeCustomViewModel>
|
public class MathExpressionNode : Node<string, MathExpressionNodeCustomViewModel>
|
||||||
{
|
{
|
||||||
private readonly IFormulaChecker _checker;
|
private readonly IFormulaChecker _checker;
|
||||||
@ -15,7 +15,6 @@ public class MathExpressionNode : Node<string, MathExpressionNodeCustomViewModel
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public MathExpressionNode(INoStringEvaluator evaluator, IFormulaChecker checker)
|
public MathExpressionNode(INoStringEvaluator evaluator, IFormulaChecker checker)
|
||||||
: base("Math Expression", "Outputs the result of a math expression.")
|
|
||||||
{
|
{
|
||||||
_evaluator = evaluator;
|
_evaluator = evaluator;
|
||||||
_checker = checker;
|
_checker = checker;
|
||||||
|
|||||||
@ -8,7 +8,6 @@ public class MaxNumericsNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public MaxNumericsNode()
|
public MaxNumericsNode()
|
||||||
: base("Max", "Outputs the largest of the connected numeric values.")
|
|
||||||
{
|
{
|
||||||
Values = CreateInputPinCollection<Numeric>("Values", 2);
|
Values = CreateInputPinCollection<Numeric>("Values", 2);
|
||||||
Max = CreateOutputPin<Numeric>("Max");
|
Max = CreateOutputPin<Numeric>("Max");
|
||||||
|
|||||||
@ -8,7 +8,6 @@ public class MinNumericsNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public MinNumericsNode()
|
public MinNumericsNode()
|
||||||
: base("Min", "Outputs the smallest of the connected numeric values.")
|
|
||||||
{
|
{
|
||||||
Values = CreateInputPinCollection<Numeric>("Values", 2);
|
Values = CreateInputPinCollection<Numeric>("Values", 2);
|
||||||
Min = CreateOutputPin<Numeric>("Min");
|
Min = CreateOutputPin<Numeric>("Min");
|
||||||
|
|||||||
@ -19,7 +19,6 @@ public class RangeNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public RangeNode()
|
public RangeNode()
|
||||||
: base("Range", "Selects the best integer value in the given range by the given percentage")
|
|
||||||
{
|
{
|
||||||
Min = CreateInputPin<Numeric>("Min");
|
Min = CreateInputPin<Numeric>("Min");
|
||||||
Max = CreateInputPin<Numeric>("Max");
|
Max = CreateInputPin<Numeric>("Max");
|
||||||
|
|||||||
@ -5,7 +5,7 @@ namespace Artemis.VisualScripting.Nodes.Mathematics;
|
|||||||
[Node("Round", "Outputs a rounded numeric value.", "Mathematics", InputType = typeof(Numeric), OutputType = typeof(Numeric))]
|
[Node("Round", "Outputs a rounded numeric value.", "Mathematics", InputType = typeof(Numeric), OutputType = typeof(Numeric))]
|
||||||
public class RoundNode : Node
|
public class RoundNode : Node
|
||||||
{
|
{
|
||||||
public RoundNode() : base("Round", "Outputs a rounded numeric value.")
|
public RoundNode()
|
||||||
{
|
{
|
||||||
Input = CreateInputPin<Numeric>();
|
Input = CreateInputPin<Numeric>();
|
||||||
Output = CreateOutputPin<Numeric>();
|
Output = CreateOutputPin<Numeric>();
|
||||||
|
|||||||
@ -17,7 +17,6 @@ public class SaturateNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public SaturateNode()
|
public SaturateNode()
|
||||||
: base("Saturate", "Clamps the value to be in between 0 and 1")
|
|
||||||
{
|
{
|
||||||
Value = CreateInputPin<Numeric>();
|
Value = CreateInputPin<Numeric>();
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,6 @@ public class SumNumericsNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public SumNumericsNode()
|
public SumNumericsNode()
|
||||||
: base("Sum", "Sums the connected numeric values.")
|
|
||||||
{
|
{
|
||||||
Values = CreateInputPinCollection<Numeric>("Values", 2);
|
Values = CreateInputPinCollection<Numeric>("Values", 2);
|
||||||
Sum = CreateOutputPin<Numeric>("Sum");
|
Sum = CreateOutputPin<Numeric>("Sum");
|
||||||
|
|||||||
@ -8,7 +8,6 @@ public class AndNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public AndNode()
|
public AndNode()
|
||||||
: base("And", "Checks if all inputs are true.")
|
|
||||||
{
|
{
|
||||||
Input = CreateInputPinCollection<bool>();
|
Input = CreateInputPinCollection<bool>();
|
||||||
Result = CreateOutputPin<bool>();
|
Result = CreateOutputPin<bool>();
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace Artemis.VisualScripting.Nodes.Operators;
|
|||||||
[Node("Enum Equals", "Determines the equality between an input and a selected enum value", "Operators", InputType = typeof(Enum), OutputType = typeof(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<long, EnumEqualsNodeCustomViewModel>
|
public class EnumEqualsNode : Node<long, EnumEqualsNodeCustomViewModel>
|
||||||
{
|
{
|
||||||
public EnumEqualsNode() : base("Enum Equals", "Determines the equality between an input and a selected enum value")
|
public EnumEqualsNode()
|
||||||
{
|
{
|
||||||
InputPin = CreateInputPin<Enum>();
|
InputPin = CreateInputPin<Enum>();
|
||||||
OutputPin = CreateOutputPin<bool>();
|
OutputPin = CreateOutputPin<bool>();
|
||||||
|
|||||||
@ -8,7 +8,6 @@ public class EqualsNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public EqualsNode()
|
public EqualsNode()
|
||||||
: base("Equals", "Checks if the two inputs are equals.")
|
|
||||||
{
|
{
|
||||||
Input1 = CreateInputPin<object>();
|
Input1 = CreateInputPin<object>();
|
||||||
Input2 = CreateInputPin<object>();
|
Input2 = CreateInputPin<object>();
|
||||||
|
|||||||
@ -9,7 +9,6 @@ public class GreaterThanNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public GreaterThanNode()
|
public GreaterThanNode()
|
||||||
: base("Greater than", "Checks if the first input is greater than the second.")
|
|
||||||
{
|
{
|
||||||
Input1 = CreateInputPin<object>();
|
Input1 = CreateInputPin<object>();
|
||||||
Input2 = CreateInputPin<object>();
|
Input2 = CreateInputPin<object>();
|
||||||
|
|||||||
@ -9,7 +9,6 @@ public class LessThanNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public LessThanNode()
|
public LessThanNode()
|
||||||
: base("Less than", "Checks if the first input is less than the second.")
|
|
||||||
{
|
{
|
||||||
Input1 = CreateInputPin<object>();
|
Input1 = CreateInputPin<object>();
|
||||||
Input2 = CreateInputPin<object>();
|
Input2 = CreateInputPin<object>();
|
||||||
|
|||||||
@ -8,7 +8,6 @@ public class NegateNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public NegateNode()
|
public NegateNode()
|
||||||
: base("Negate", "Negates the boolean.")
|
|
||||||
{
|
{
|
||||||
Input = CreateInputPin<bool>();
|
Input = CreateInputPin<bool>();
|
||||||
Output = CreateOutputPin<bool>();
|
Output = CreateOutputPin<bool>();
|
||||||
|
|||||||
@ -8,7 +8,6 @@ public class OrNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public OrNode()
|
public OrNode()
|
||||||
: base("Or", "Checks if any inputs are true.")
|
|
||||||
{
|
{
|
||||||
Input = CreateInputPinCollection<bool>();
|
Input = CreateInputPinCollection<bool>();
|
||||||
Result = CreateOutputPin<bool>();
|
Result = CreateOutputPin<bool>();
|
||||||
|
|||||||
@ -8,7 +8,6 @@ public class XorNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public XorNode()
|
public XorNode()
|
||||||
: base("Exclusive Or", "Checks if one of the inputs is true.")
|
|
||||||
{
|
{
|
||||||
Input = CreateInputPinCollection<bool>();
|
Input = CreateInputPinCollection<bool>();
|
||||||
Result = CreateOutputPin<bool>();
|
Result = CreateOutputPin<bool>();
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace Artemis.VisualScripting.Nodes.Static;
|
|||||||
[Node("Display Value", "Displays an input value for testing purposes.", "Static", InputType = typeof(object))]
|
[Node("Display Value", "Displays an input value for testing purposes.", "Static", InputType = typeof(object))]
|
||||||
public class DisplayValueNode : Node<string, DisplayValueNodeCustomViewModel>
|
public class DisplayValueNode : Node<string, DisplayValueNodeCustomViewModel>
|
||||||
{
|
{
|
||||||
public DisplayValueNode() : base("Display Value", "Displays an input value for testing purposes.")
|
public DisplayValueNode()
|
||||||
{
|
{
|
||||||
Input = CreateInputPin<object>();
|
Input = CreateInputPin<object>();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,6 @@ public class RandomNumericValueNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public RandomNumericValueNode()
|
public RandomNumericValueNode()
|
||||||
: base("Random", "Generates a random value between 0 and 1")
|
|
||||||
{
|
{
|
||||||
Output = CreateOutputPin<Numeric>();
|
Output = CreateOutputPin<Numeric>();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,8 +9,8 @@ public class StaticBooleanValueNode : Node<bool, StaticBooleanValueNodeCustomVie
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public StaticBooleanValueNode()
|
public StaticBooleanValueNode()
|
||||||
: base("Boolean", "Outputs a configurable static boolean value.")
|
|
||||||
{
|
{
|
||||||
|
Name = "Boolean";
|
||||||
Output = CreateOutputPin<bool>();
|
Output = CreateOutputPin<bool>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,8 +9,8 @@ public class StaticNumericValueNode : Node<Numeric, StaticNumericValueNodeCustom
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public StaticNumericValueNode()
|
public StaticNumericValueNode()
|
||||||
: base("Numeric", "Outputs a configurable numeric value.")
|
|
||||||
{
|
{
|
||||||
|
Name = "Numeric";
|
||||||
Output = CreateOutputPin<Numeric>();
|
Output = CreateOutputPin<Numeric>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,8 +10,8 @@ public class StaticSKColorValueNode : Node<SKColor, StaticSKColorValueNodeCustom
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public StaticSKColorValueNode()
|
public StaticSKColorValueNode()
|
||||||
: base("Color", "Outputs a configurable color value.")
|
|
||||||
{
|
{
|
||||||
|
Name = "Color";
|
||||||
Output = CreateOutputPin<SKColor>();
|
Output = CreateOutputPin<SKColor>();
|
||||||
Storage = new SKColor(255, 0, 0);
|
Storage = new SKColor(255, 0, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,8 +9,8 @@ public class StaticStringValueNode : Node<string, StaticStringValueNodeCustomVie
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public StaticStringValueNode()
|
public StaticStringValueNode()
|
||||||
: base("Text", "Outputs a configurable text value.")
|
|
||||||
{
|
{
|
||||||
|
Name = "Text";
|
||||||
Output = CreateOutputPin<string>();
|
Output = CreateOutputPin<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,6 @@ namespace Artemis.VisualScripting.Nodes.Text;
|
|||||||
public class StringContainsNode : Node
|
public class StringContainsNode : Node
|
||||||
{
|
{
|
||||||
public StringContainsNode()
|
public StringContainsNode()
|
||||||
: base("Contains", "Checks whether the first input is contained in the second input.")
|
|
||||||
{
|
{
|
||||||
Input1 = CreateInputPin<string>();
|
Input1 = CreateInputPin<string>();
|
||||||
Input2 = CreateInputPin<string>();
|
Input2 = CreateInputPin<string>();
|
||||||
|
|||||||
@ -8,7 +8,6 @@ public class StringFormatNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public StringFormatNode()
|
public StringFormatNode()
|
||||||
: base("Format", "Formats the input string.")
|
|
||||||
{
|
{
|
||||||
Format = CreateInputPin<string>("Format");
|
Format = CreateInputPin<string>("Format");
|
||||||
Values = CreateInputPinCollection<object>("Values");
|
Values = CreateInputPinCollection<object>("Values");
|
||||||
|
|||||||
@ -7,7 +7,6 @@ namespace Artemis.VisualScripting.Nodes.Text;
|
|||||||
public class StringLengthNode : Node
|
public class StringLengthNode : Node
|
||||||
{
|
{
|
||||||
public StringLengthNode()
|
public StringLengthNode()
|
||||||
: base("Text Length", "Outputs text length.")
|
|
||||||
{
|
{
|
||||||
Input1 = CreateInputPin<string>();
|
Input1 = CreateInputPin<string>();
|
||||||
Result = CreateOutputPin<Numeric>();
|
Result = CreateOutputPin<Numeric>();
|
||||||
|
|||||||
@ -7,7 +7,6 @@ namespace Artemis.VisualScripting.Nodes.Text;
|
|||||||
public class StringNullOrEmptyNode : Node
|
public class StringNullOrEmptyNode : Node
|
||||||
{
|
{
|
||||||
public StringNullOrEmptyNode()
|
public StringNullOrEmptyNode()
|
||||||
: base("Text is empty", "Outputs true if empty")
|
|
||||||
{
|
{
|
||||||
Input1 = CreateInputPin<string>();
|
Input1 = CreateInputPin<string>();
|
||||||
Output1 = CreateOutputPin<bool>();
|
Output1 = CreateOutputPin<bool>();
|
||||||
|
|||||||
@ -10,7 +10,7 @@ public class StringRegexMatchNode : Node
|
|||||||
private Regex? _regex;
|
private Regex? _regex;
|
||||||
private Exception? _exception;
|
private Exception? _exception;
|
||||||
|
|
||||||
public StringRegexMatchNode() : base("Regex Match", "Checks provided regex pattern matches the input.")
|
public StringRegexMatchNode()
|
||||||
{
|
{
|
||||||
Pattern = CreateInputPin<string>("Pattern");
|
Pattern = CreateInputPin<string>("Pattern");
|
||||||
Input = CreateInputPin<string>("Input");
|
Input = CreateInputPin<string>("Input");
|
||||||
|
|||||||
@ -25,7 +25,6 @@ public class DelayNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public DelayNode()
|
public DelayNode()
|
||||||
: base("Delay", "Delays the resolution of the input pin(s) for the given time after each update")
|
|
||||||
{
|
{
|
||||||
Delay = CreateInputPin<Numeric>("Delay");
|
Delay = CreateInputPin<Numeric>("Delay");
|
||||||
Input = CreateInputPinCollection(typeof(object), initialCount: 0);
|
Input = CreateInputPinCollection(typeof(object), initialCount: 0);
|
||||||
|
|||||||
@ -17,7 +17,6 @@ public class EdgeNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public EdgeNode()
|
public EdgeNode()
|
||||||
: base("Edge", "Outputs true on each edge when the input changes")
|
|
||||||
{
|
{
|
||||||
Input = CreateInputPin<bool>();
|
Input = CreateInputPin<bool>();
|
||||||
Output = CreateOutputPin<bool>();
|
Output = CreateOutputPin<bool>();
|
||||||
|
|||||||
@ -18,7 +18,6 @@ public class FlipFlopNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public FlipFlopNode()
|
public FlipFlopNode()
|
||||||
: base("FlipFlop", "Inverts the output when the input changes from false to true")
|
|
||||||
{
|
{
|
||||||
Input = CreateInputPin<bool>();
|
Input = CreateInputPin<bool>();
|
||||||
Output = CreateOutputPin<bool>();
|
Output = CreateOutputPin<bool>();
|
||||||
|
|||||||
@ -25,7 +25,6 @@ public class LatchNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public LatchNode()
|
public LatchNode()
|
||||||
: base("Latch", "Only passes the input to the output as long as the control-pin is true. If the control pin is false the last passed value is provided.")
|
|
||||||
{
|
{
|
||||||
Control = CreateInputPin<bool>("Control");
|
Control = CreateInputPin<bool>("Control");
|
||||||
Input = CreateInputPinCollection(typeof(object), initialCount: 0);
|
Input = CreateInputPinCollection(typeof(object), initialCount: 0);
|
||||||
|
|||||||
@ -25,7 +25,6 @@ public class SequencerNode : Node
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public SequencerNode()
|
public SequencerNode()
|
||||||
: base("Sequencer", "Advances on input every time the control has a rising edge (change to true)")
|
|
||||||
{
|
{
|
||||||
_currentType = typeof(object);
|
_currentType = typeof(object);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user