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:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version-suffix: ${{ steps.get-version.outputs.version-suffix }}
|
||||
version-number: ${{ steps.get-version.outputs.version-number }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
@ -22,9 +22,12 @@ jobs:
|
||||
run: |
|
||||
$MidnightUtc = [DateTime]::UtcNow.Date
|
||||
$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
|
||||
$VersionSuffix = "$BranchName.$($MidnightUtc.ToString("yyyyMMdd")).$NumberOfCommitsToday"
|
||||
Write-Output "::set-output name=version-suffix::$VersionSuffix"
|
||||
$VersionNumber = "$ApiVersion.$($MidnightUtc.ToString("yyyy.MMdd")).$NumberOfCommitsToday"
|
||||
# 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:
|
||||
name: Publish Nuget Packages
|
||||
@ -38,8 +41,8 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- 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
|
||||
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
|
||||
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>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<PackageId>ArtemisRGB.Core</PackageId>
|
||||
<!-- API Version -->
|
||||
<VersionPrefix>1.0.0.0</VersionPrefix>
|
||||
<PluginApiVersion>1</PluginApiVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Artemis.Storage\Artemis.Storage.csproj"/>
|
||||
<ProjectReference Condition="'$(BuildingNuget)' == 'True'" Update="..\Artemis.Storage\Artemis.Storage.csproj" PrivateAssets="All"/>
|
||||
<!--Used to embed the above PluginApiVersion property into the assembly as metadata-->
|
||||
<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
|
||||
|
||||
@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Artemis.Core.JsonConverters;
|
||||
using Artemis.Core.Services;
|
||||
@ -61,7 +62,8 @@ public static class Constants
|
||||
/// <summary>
|
||||
/// The current API version for plugins
|
||||
/// </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>
|
||||
/// The plugin info used by core components of Artemis
|
||||
|
||||
@ -16,12 +16,13 @@ namespace Artemis.Core;
|
||||
/// </summary>
|
||||
public sealed class Layer : RenderProfileElement
|
||||
{
|
||||
private readonly List<Layer> _renderCopies;
|
||||
private LayerGeneralProperties _general;
|
||||
private readonly List<Layer> _renderCopies = new();
|
||||
private LayerGeneralProperties _general = new();
|
||||
private LayerTransformProperties _transform = new();
|
||||
private BaseLayerBrush? _layerBrush;
|
||||
private LayerShape? _layerShape;
|
||||
private List<ArtemisLed> _leds;
|
||||
private LayerTransformProperties _transform;
|
||||
private List<ArtemisLed> _leds = new();
|
||||
private List<LedEntity> _missingLeds = new();
|
||||
|
||||
/// <summary>
|
||||
/// 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;
|
||||
Name = name;
|
||||
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);
|
||||
|
||||
Adapter = new LayerAdapter(this);
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
@ -63,16 +57,9 @@ public sealed class Layer : RenderProfileElement
|
||||
|
||||
Profile = profile;
|
||||
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);
|
||||
|
||||
Adapter = new LayerAdapter(this);
|
||||
|
||||
Load();
|
||||
Initialize();
|
||||
}
|
||||
@ -327,6 +314,7 @@ public sealed class Layer : RenderProfileElement
|
||||
|
||||
// LEDs
|
||||
LayerEntity.Leds.Clear();
|
||||
SaveMissingLeds();
|
||||
foreach (ArtemisLed artemisLed in Leds)
|
||||
{
|
||||
LedEntity ledEntity = new()
|
||||
@ -786,6 +774,8 @@ public sealed class Layer : RenderProfileElement
|
||||
a.RgbLed.Id.ToString() == ledEntity.LedName);
|
||||
if (match != null)
|
||||
leds.Add(match);
|
||||
else
|
||||
_missingLeds.Add(ledEntity);
|
||||
}
|
||||
|
||||
_leds = leds;
|
||||
@ -793,6 +783,11 @@ public sealed class Layer : RenderProfileElement
|
||||
CalculateRenderProperties();
|
||||
}
|
||||
|
||||
private void SaveMissingLeds()
|
||||
{
|
||||
LayerEntity.Leds.AddRange(_missingLeds.Except(LayerEntity.Leds, LedEntity.LedEntityComparer));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Brush management
|
||||
|
||||
@ -191,7 +191,7 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether this plugin is compatible with the current operating system and API version
|
||||
/// </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)}";
|
||||
|
||||
|
||||
@ -75,8 +75,9 @@ internal class NodeService : INodeService
|
||||
string name = nodeAttribute?.Name ?? nodeType.Name;
|
||||
string description = nodeAttribute?.Description ?? string.Empty;
|
||||
string category = nodeAttribute?.Category ?? string.Empty;
|
||||
|
||||
NodeData nodeData = new(plugin, nodeType, name, description, category, nodeAttribute?.InputType, nodeAttribute?.OutputType, (s, e) => CreateNode(s, e, nodeType));
|
||||
string helpUrl = nodeAttribute?.HelpUrl ?? string.Empty;
|
||||
|
||||
NodeData nodeData = new(plugin, nodeType, name, description, category, helpUrl, nodeAttribute?.InputType, nodeAttribute?.OutputType, (s, e) => CreateNode(s, e, nodeType));
|
||||
return NodeTypeStore.Add(nodeData);
|
||||
}
|
||||
|
||||
|
||||
@ -18,12 +18,12 @@ public interface INode : INotifyPropertyChanged, IBreakableModel
|
||||
/// <summary>
|
||||
/// Gets the name of the node
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the description of the node
|
||||
/// </summary>
|
||||
string Description { get; }
|
||||
string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether the node is the exit node of the script
|
||||
@ -44,6 +44,11 @@ public interface INode : INotifyPropertyChanged, IBreakableModel
|
||||
/// Gets or sets the Y-position of the node
|
||||
/// </summary>
|
||||
public double Y { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the help URL of the node
|
||||
/// </summary>
|
||||
string HelpUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a read-only collection of the pins on this node
|
||||
|
||||
@ -24,6 +24,11 @@ public class NodeAttribute : Attribute
|
||||
/// </summary>
|
||||
public string Category { get; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the help URL of the node
|
||||
/// </summary>
|
||||
public string HelpUrl { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the primary input type of the node
|
||||
/// </summary>
|
||||
@ -65,5 +70,16 @@ public class NodeAttribute : Attribute
|
||||
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
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Artemis.Storage.Entities.Profile.Nodes;
|
||||
using Castle.Core.Internal;
|
||||
|
||||
namespace Artemis.Core;
|
||||
|
||||
@ -10,13 +11,14 @@ public class NodeData
|
||||
{
|
||||
#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;
|
||||
Type = type;
|
||||
Name = name;
|
||||
Description = description;
|
||||
Category = category;
|
||||
HelpUrl = helpUrl;
|
||||
InputType = inputType;
|
||||
OutputType = outputType;
|
||||
_create = create;
|
||||
@ -34,7 +36,15 @@ public class NodeData
|
||||
/// <returns>The returning node of type <see cref="Type" /></returns>
|
||||
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
|
||||
@ -101,6 +111,11 @@ public class NodeData
|
||||
/// </summary>
|
||||
public string Category { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the help URL of the node this data represents
|
||||
/// </summary>
|
||||
public string HelpUrl { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the primary input type of the node this data represents
|
||||
/// </summary>
|
||||
|
||||
@ -46,7 +46,7 @@ public abstract class Node : BreakableModel, INode
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
protected set => SetAndNotify(ref _name, value);
|
||||
set => SetAndNotify(ref _name, value);
|
||||
}
|
||||
|
||||
private string _description;
|
||||
@ -55,7 +55,7 @@ public abstract class Node : BreakableModel, INode
|
||||
public string Description
|
||||
{
|
||||
get => _description;
|
||||
protected set => SetAndNotify(ref _description, value);
|
||||
set => SetAndNotify(ref _description, value);
|
||||
}
|
||||
|
||||
private double _x;
|
||||
@ -76,6 +76,13 @@ public abstract class Node : BreakableModel, INode
|
||||
set => SetAndNotify(ref _y, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string HelpUrl
|
||||
{
|
||||
get => _helpUrl;
|
||||
set => SetAndNotify(ref _helpUrl, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual bool IsExitNode => false;
|
||||
|
||||
@ -88,6 +95,7 @@ public abstract class Node : BreakableModel, INode
|
||||
public IReadOnlyCollection<IPin> Pins => new ReadOnlyCollection<IPin>(_pins);
|
||||
|
||||
private readonly List<IPinCollection> _pinCollections = new();
|
||||
private string _helpUrl;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyCollection<IPinCollection> PinCollections => new ReadOnlyCollection<IPinCollection>(_pinCollections);
|
||||
@ -106,6 +114,7 @@ public abstract class Node : BreakableModel, INode
|
||||
{
|
||||
_name = string.Empty;
|
||||
_description = string.Empty;
|
||||
_helpUrl = string.Empty;
|
||||
_id = Guid.NewGuid();
|
||||
}
|
||||
|
||||
@ -116,6 +125,7 @@ public abstract class Node : BreakableModel, INode
|
||||
{
|
||||
_name = name;
|
||||
_description = description;
|
||||
_helpUrl = string.Empty;
|
||||
_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
|
||||
{
|
||||
#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 DeviceIdentifier { get; set; }
|
||||
|
||||
|
||||
@ -4,6 +4,22 @@ namespace Artemis.Storage.Entities.Profile.Nodes;
|
||||
|
||||
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 Guid SourceNode { get; set; }
|
||||
public Guid TargetNode { get; set; }
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Artemis.Storage.Entities.Profile.Nodes;
|
||||
|
||||
@ -10,6 +11,22 @@ public class NodeEntity
|
||||
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 string Type { get; set; }
|
||||
public Guid PluginId { get; set; }
|
||||
|
||||
@ -2,6 +2,17 @@
|
||||
|
||||
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 Direction { set; get; }
|
||||
public int Amount { get; set; }
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
|
||||
namespace Artemis.UI.Shared.Services.NodeEditor.Commands;
|
||||
@ -36,7 +37,8 @@ public class AddNode : INodeEditorCommand, IDisposable
|
||||
/// <inheritdoc />
|
||||
public void Execute()
|
||||
{
|
||||
_nodeScript.AddNode(_node);
|
||||
if (!_nodeScript.Nodes.Contains(_node))
|
||||
_nodeScript.AddNode(_node);
|
||||
_isRemoved = false;
|
||||
}
|
||||
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
|
||||
<!-- Add Styles Here -->
|
||||
<Style Selector="TextBox.condensed">
|
||||
<Setter Property="Padding" Value="2" />
|
||||
<Setter Property="Padding" Value="6 1" />
|
||||
<Setter Property="FontSize" Value="13" />
|
||||
<Setter Property="MinHeight" Value="24" />
|
||||
</Style>
|
||||
|
||||
@ -8,9 +8,10 @@
|
||||
|
||||
|
||||
<!-- Add Controls for Previewer Here -->
|
||||
<TextBox Text="99999999"
|
||||
<TextBox Text="99999999"
|
||||
attached:TextBoxAssist.PrefixText="%"
|
||||
attached:TextBoxAssist.SuffixText="%"></TextBox>
|
||||
attached:TextBoxAssist.SuffixText="%">
|
||||
</TextBox>
|
||||
<controls:NumberBox Value="99999999"
|
||||
attached:NumberBoxAssist.PrefixText="%"
|
||||
attached:NumberBoxAssist.SuffixText="%" />
|
||||
@ -30,80 +31,95 @@
|
||||
|
||||
<!-- Add Styles Here -->
|
||||
<Style Selector="TextBox">
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<DataValidationErrors>
|
||||
<Panel>
|
||||
<!-- This is flipped (scaleY(-1)) for the elevation brush effect
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<DataValidationErrors>
|
||||
<Panel>
|
||||
<!-- This is flipped (scaleY(-1)) for the elevation brush effect
|
||||
-->
|
||||
<Border
|
||||
Name="PART_BorderElement"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
MinWidth="{TemplateBinding MinWidth}"
|
||||
MinHeight="{TemplateBinding MinHeight}"
|
||||
RenderTransform="scaleY(-1)"
|
||||
CornerRadius="{TemplateBinding CornerRadius}"/>
|
||||
<Border
|
||||
Name="PART_BorderElement"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
MinWidth="{TemplateBinding MinWidth}"
|
||||
MinHeight="{TemplateBinding MinHeight}"
|
||||
RenderTransform="scaleY(-1)"
|
||||
CornerRadius="{TemplateBinding CornerRadius}" />
|
||||
|
||||
<Border
|
||||
Margin="{TemplateBinding BorderThickness}">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto" >
|
||||
<ContentPresenter Grid.Column="0" Content="{TemplateBinding InnerLeftContent}"/>
|
||||
<DockPanel x:Name="PART_InnerDockPanel" Grid.Column="1" Margin="{TemplateBinding Padding}">
|
||||
<TextBlock Name="PART_Prefix"
|
||||
Text="{TemplateBinding attached:TextBoxAssist.PrefixText}"
|
||||
IsHitTestVisible="False"
|
||||
DockPanel.Dock="Left"/>
|
||||
<TextBlock Name="PART_FloatingWatermark"
|
||||
<Border
|
||||
Margin="{TemplateBinding BorderThickness}">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||
<ContentPresenter Grid.Column="0" Content="{TemplateBinding InnerLeftContent}" />
|
||||
<Grid x:Name="PART_InnerGrid"
|
||||
Grid.Column="1"
|
||||
RowDefinitions="Auto,Auto"
|
||||
ColumnDefinitions="Auto,*,Auto"
|
||||
Cursor="IBeam"
|
||||
Margin="{TemplateBinding Padding}">
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.ColumnSpan="3"
|
||||
Name="PART_FloatingWatermark"
|
||||
Foreground="{DynamicResource SystemAccentColor}"
|
||||
FontSize="{TemplateBinding FontSize}"
|
||||
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>
|
||||
Text="{TemplateBinding Watermark}" />
|
||||
|
||||
<TextBlock Name="PART_Suffix"
|
||||
Text="{TemplateBinding attached:TextBoxAssist.SuffixText}"
|
||||
<TextBlock Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Name="PART_Prefix"
|
||||
Text="{TemplateBinding attached:TextBoxAssist.PrefixText}"
|
||||
IsVisible="{TemplateBinding attached:TextBoxAssist.PrefixText, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||
IsHitTestVisible="False"
|
||||
HorizontalAlignment="Right"
|
||||
DockPanel.Dock="Right"/>
|
||||
</DockPanel>
|
||||
<ContentPresenter Grid.Column="2" Content="{TemplateBinding InnerRightContent}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Panel>
|
||||
</DataValidationErrors>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
DockPanel.Dock="Left" />
|
||||
|
||||
<ScrollViewer Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
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 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 Selector="TextBox /template/ TextBlock#PART_Prefix">
|
||||
<Style Selector="TextBox /template/ TextBlock#PART_Prefix">
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextControlForegroundDisabled}"></Setter>
|
||||
<Setter Property="Margin" Value="-4 0 4 0"></Setter>
|
||||
</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>
|
||||
<Grid RowDefinitions="60,Auto,Auto,*,Auto,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"
|
||||
FontSize="24"
|
||||
VerticalAlignment="Center"
|
||||
@ -46,6 +46,8 @@
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip.Tip="View website"
|
||||
ToolTip.Placement="Top"
|
||||
ToolTip.VerticalOffset="-5"
|
||||
NavigateUri="https://artemis-rgb.com">
|
||||
<avalonia:MaterialIcon Kind="Web" Width="20" Height="20" />
|
||||
</controls:HyperlinkButton>
|
||||
@ -53,6 +55,8 @@
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip.Tip="View GitHub repository"
|
||||
ToolTip.Placement="Top"
|
||||
ToolTip.VerticalOffset="-5"
|
||||
NavigateUri="https://github.com/Artemis-RGB/Artemis">
|
||||
<avalonia:MaterialIcon Kind="Github" Width="20" Height="20" />
|
||||
</controls:HyperlinkButton>
|
||||
@ -60,6 +64,8 @@
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip.Tip="View Wiki"
|
||||
ToolTip.Placement="Top"
|
||||
ToolTip.VerticalOffset="-5"
|
||||
NavigateUri="https://wiki.artemis-rgb.com">
|
||||
<avalonia:MaterialIcon Kind="BookOpenOutline" Width="20" Height="20" />
|
||||
</controls:HyperlinkButton>
|
||||
@ -67,6 +73,8 @@
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip.Tip="Join our Discord"
|
||||
ToolTip.Placement="Top"
|
||||
ToolTip.VerticalOffset="-5"
|
||||
NavigateUri="https://discord.gg/S3MVaC9">
|
||||
<avalonia:MaterialIcon Kind="Chat" Width="20" Height="20" />
|
||||
</controls:HyperlinkButton>
|
||||
@ -74,6 +82,8 @@
|
||||
Width="44"
|
||||
Height="44"
|
||||
ToolTip.Tip="View donation options"
|
||||
ToolTip.Placement="Top"
|
||||
ToolTip.VerticalOffset="-5"
|
||||
NavigateUri="https://wiki.artemis-rgb.com/en/donating">
|
||||
<avalonia:MaterialIcon Kind="Gift" Width="20" Height="20" />
|
||||
</controls:HyperlinkButton>
|
||||
|
||||
@ -24,11 +24,6 @@
|
||||
Stroke="{CompiledBinding CableColor, Converter={StaticResource ColorToSolidColorBrushConverter}}"
|
||||
StrokeThickness="4"
|
||||
StrokeLineCap="Round">
|
||||
<Path.Transitions>
|
||||
<Transitions>
|
||||
<ThicknessTransition Property="Margin" Duration="200"></ThicknessTransition>
|
||||
</Transitions>
|
||||
</Path.Transitions>
|
||||
<Path.Data>
|
||||
<PathGeometry>
|
||||
<PathGeometry.Figures>
|
||||
@ -47,8 +42,6 @@
|
||||
BorderThickness="2"
|
||||
CornerRadius="3"
|
||||
Padding="4"
|
||||
Canvas.Left="{CompiledBinding ValuePoint.X}"
|
||||
Canvas.Top="{CompiledBinding ValuePoint.Y}"
|
||||
IsVisible="{CompiledBinding DisplayValue}">
|
||||
<ContentControl Content="{CompiledBinding FromViewModel.Pin.PinValue}">
|
||||
<ContentControl.DataTemplates>
|
||||
|
||||
@ -8,6 +8,7 @@ using Avalonia.Input;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.ReactiveUI;
|
||||
using Avalonia.Rendering;
|
||||
using ReactiveUI;
|
||||
|
||||
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);
|
||||
|
||||
ViewModel.WhenAnyValue(vm => vm.FromPoint).Subscribe(_ => Update()).DisposeWith(d);
|
||||
ViewModel.WhenAnyValue(vm => vm.ToPoint).Subscribe(_ => Update()).DisposeWith(d);
|
||||
Update();
|
||||
ViewModel.WhenAnyValue(vm => vm.FromPoint).Subscribe(_ => Update(true)).DisposeWith(d);
|
||||
ViewModel.WhenAnyValue(vm => vm.ToPoint).Subscribe(_ => Update(false)).DisposeWith(d);
|
||||
Update(true);
|
||||
});
|
||||
}
|
||||
|
||||
@ -40,10 +41,12 @@ public class CableView : ReactiveUserControl<CableViewModel>
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
private void Update(bool from)
|
||||
{
|
||||
// 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();
|
||||
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.Point2 = new Point(ViewModel.ToPoint.X - CABLE_OFFSET, 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)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using Artemis.Core;
|
||||
@ -27,7 +28,6 @@ public class CableViewModel : ActivatableViewModelBase
|
||||
private PinViewModel? _fromViewModel;
|
||||
private ObservableAsPropertyHelper<Point>? _toPoint;
|
||||
private PinViewModel? _toViewModel;
|
||||
private ObservableAsPropertyHelper<Point>? _valuePoint;
|
||||
|
||||
public CableViewModel(NodeScriptViewModel nodeScriptViewModel, IPin from, IPin to, ISettingsService settingsService)
|
||||
{
|
||||
@ -63,12 +63,7 @@ public class CableViewModel : ActivatableViewModelBase
|
||||
.Switch()
|
||||
.ToProperty(this, vm => vm.ToPoint)
|
||||
.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)
|
||||
_connected = this.WhenAnyValue(vm => vm.FromPoint, vm => vm.ToPoint)
|
||||
.Select(tuple => tuple.Item1 != new Point(0, 0) && tuple.Item2 != new Point(0, 0))
|
||||
@ -104,11 +99,10 @@ public class CableViewModel : ActivatableViewModelBase
|
||||
}
|
||||
|
||||
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 ToPoint => _toPoint?.Value ?? new Point();
|
||||
public Point ValuePoint => _valuePoint?.Value ?? new Point();
|
||||
public Color CableColor => _cableColor?.Value ?? new Color(255, 255, 255, 255);
|
||||
|
||||
public void UpdateDisplayValue(bool hoveringOver)
|
||||
|
||||
@ -30,6 +30,8 @@
|
||||
<KeyBinding Command="{CompiledBinding ClearSelection}" Gesture="Escape" />
|
||||
<KeyBinding Command="{CompiledBinding DeleteSelected}" Gesture="Delete" />
|
||||
<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.Redo}" Gesture="Ctrl+Y" />
|
||||
</UserControl.KeyBindings>
|
||||
|
||||
@ -14,6 +14,7 @@ using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.ReactiveUI;
|
||||
using Avalonia.Threading;
|
||||
using Avalonia.VisualTree;
|
||||
using DynamicData.Binding;
|
||||
using ReactiveUI;
|
||||
|
||||
@ -39,6 +40,8 @@ public class NodeScriptView : ReactiveUserControl<NodeScriptViewModel>
|
||||
|
||||
_zoomBorder.AddHandler(PointerReleasedEvent, CanvasOnPointerReleased, 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 =>
|
||||
{
|
||||
ViewModel!.AutoFitRequested += ViewModelOnAutoFitRequested;
|
||||
@ -67,6 +70,12 @@ public class NodeScriptView : ReactiveUserControl<NodeScriptViewModel>
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void ZoomOnPointerMoved(object? sender, PointerEventArgs e)
|
||||
{
|
||||
if (ViewModel != null)
|
||||
ViewModel.PastePosition = e.GetPosition(_grid);
|
||||
}
|
||||
|
||||
private void ShowPickerAt(Point point)
|
||||
{
|
||||
if (ViewModel == null)
|
||||
|
||||
@ -6,9 +6,12 @@ using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Events;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Models;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Screens.VisualScripting.Pins;
|
||||
using Artemis.UI.Shared;
|
||||
@ -16,6 +19,7 @@ using Artemis.UI.Shared.Services.NodeEditor;
|
||||
using Artemis.UI.Shared.Services.NodeEditor.Commands;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.Mixins;
|
||||
using Avalonia.Input;
|
||||
using DynamicData;
|
||||
using DynamicData.Binding;
|
||||
using ReactiveUI;
|
||||
@ -24,6 +28,8 @@ namespace Artemis.UI.Screens.VisualScripting;
|
||||
|
||||
public class NodeScriptViewModel : ActivatableViewModelBase
|
||||
{
|
||||
public const string CLIPBOARD_DATA_FORMAT = "Artemis.Nodes";
|
||||
|
||||
private readonly INodeEditorService _nodeEditorService;
|
||||
private readonly INodeService _nodeService;
|
||||
private readonly SourceList<NodeViewModel> _nodeViewModels;
|
||||
@ -33,6 +39,7 @@ public class NodeScriptViewModel : ActivatableViewModelBase
|
||||
private DragCableViewModel? _dragViewModel;
|
||||
private List<NodeViewModel>? _initialNodeSelection;
|
||||
private Matrix _panMatrix;
|
||||
private Point _pastePosition;
|
||||
|
||||
public NodeScriptViewModel(NodeScript nodeScript, bool isPreview, INodeVmFactory nodeVmFactory, INodeService nodeService, INodeEditorService nodeEditorService)
|
||||
{
|
||||
@ -86,8 +93,8 @@ public class NodeScriptViewModel : ActivatableViewModelBase
|
||||
ClearSelection = ReactiveCommand.Create(ExecuteClearSelection);
|
||||
DeleteSelected = ReactiveCommand.Create(ExecuteDeleteSelected);
|
||||
DuplicateSelected = ReactiveCommand.Create(ExecuteDuplicateSelected);
|
||||
CopySelected = ReactiveCommand.Create(ExecuteCopySelected);
|
||||
PasteSelected = ReactiveCommand.Create(ExecutePasteSelected);
|
||||
CopySelected = ReactiveCommand.CreateFromTask(ExecuteCopySelected);
|
||||
PasteSelected = ReactiveCommand.CreateFromTask(ExecutePasteSelected);
|
||||
}
|
||||
|
||||
public NodeScript NodeScript { get; }
|
||||
@ -118,6 +125,12 @@ public class NodeScriptViewModel : ActivatableViewModelBase
|
||||
set => RaiseAndSetIfChanged(ref _panMatrix, value);
|
||||
}
|
||||
|
||||
public Point PastePosition
|
||||
{
|
||||
get => _pastePosition;
|
||||
set => RaiseAndSetIfChanged(ref _pastePosition, value);
|
||||
}
|
||||
|
||||
public void DeleteSelectedNodes()
|
||||
{
|
||||
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:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||
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"
|
||||
x:Class="Artemis.UI.Screens.VisualScripting.NodeView"
|
||||
x:DataType="visualScripting:NodeViewModel">
|
||||
@ -37,7 +38,7 @@
|
||||
ClipToBounds="True"
|
||||
Background="{DynamicResource ContentDialogBackground}">
|
||||
<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"
|
||||
VerticalAlignment="Center"
|
||||
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}" />
|
||||
|
||||
<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>
|
||||
</Button>
|
||||
</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))]
|
||||
public class BooleanBranchNode : Node
|
||||
{
|
||||
public BooleanBranchNode() : base("Branch", "Forwards one of two values depending on an input boolean")
|
||||
public BooleanBranchNode()
|
||||
{
|
||||
BooleanInput = CreateInputPin<bool>();
|
||||
TrueInput = CreateInputPin(typeof(object), "True");
|
||||
|
||||
@ -9,7 +9,7 @@ public class EnumSwitchNode : Node
|
||||
{
|
||||
private readonly Dictionary<Enum, InputPin> _inputPins;
|
||||
|
||||
public EnumSwitchNode() : base("Enum Branch", "desc")
|
||||
public EnumSwitchNode()
|
||||
{
|
||||
_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))]
|
||||
public class BrightenSKColorNode : Node
|
||||
{
|
||||
public BrightenSKColorNode() : base("Brighten Color", "Brightens a color by a specified amount in percent")
|
||||
public BrightenSKColorNode()
|
||||
{
|
||||
Input = CreateInputPin<SKColor>("Color");
|
||||
Percentage = CreateInputPin<Numeric>("%");
|
||||
|
||||
@ -11,7 +11,7 @@ public class ColorGradientFromPinsNode : Node
|
||||
public InputPinCollection<SKColor> Colors { 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);
|
||||
Positions = CreateInputPinCollection<Numeric>("Positions", 0);
|
||||
|
||||
@ -10,7 +10,7 @@ public class ColorGradientNode : Node<ColorGradient, ColorGradientNodeCustomView
|
||||
{
|
||||
private readonly List<InputPin> _inputPins;
|
||||
|
||||
public ColorGradientNode() : base("Color Gradient", "Outputs a color gradient with the given colors")
|
||||
public ColorGradientNode()
|
||||
{
|
||||
_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))]
|
||||
public class DarkenSKColorNode : Node
|
||||
{
|
||||
public DarkenSKColorNode() : base("Darken Color", "Darkens a color by a specified amount in percent")
|
||||
public DarkenSKColorNode()
|
||||
{
|
||||
Input = CreateInputPin<SKColor>("Color");
|
||||
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))]
|
||||
public class DesaturateSKColorNode : Node
|
||||
{
|
||||
public DesaturateSKColorNode() : base("Desaturate Color", "Desaturates a color by a specified amount in percent")
|
||||
public DesaturateSKColorNode()
|
||||
{
|
||||
Input = CreateInputPin<SKColor>("Color");
|
||||
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))]
|
||||
public class HslSKColorNode : Node
|
||||
{
|
||||
public HslSKColorNode() : base("HSL Color", "Creates a color from hue, saturation and lightness values")
|
||||
public HslSKColorNode()
|
||||
{
|
||||
H = CreateInputPin<Numeric>("H");
|
||||
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))]
|
||||
public class InvertSKColorNode : Node
|
||||
{
|
||||
public InvertSKColorNode() : base("Invert Color", "Inverts a color")
|
||||
public InvertSKColorNode()
|
||||
{
|
||||
Input = CreateInputPin<SKColor>();
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
|
||||
@ -20,8 +20,8 @@ public class LerpSKColorNode : Node
|
||||
#region Constructors
|
||||
|
||||
public LerpSKColorNode()
|
||||
: base("Lerp", "Interpolates linear between the two values A and B")
|
||||
{
|
||||
Name = "Lerp";
|
||||
A = CreateInputPin<SKColor>("A");
|
||||
B = CreateInputPin<SKColor>("B");
|
||||
T = CreateInputPin<Numeric>("T");
|
||||
|
||||
@ -10,7 +10,6 @@ public class RampSKColorNode : Node<ColorGradient, RampSKColorNodeCustomViewMode
|
||||
#region Constructors
|
||||
|
||||
public RampSKColorNode()
|
||||
: base("Color Ramp", "Maps values to colors with the use of a gradient.")
|
||||
{
|
||||
Input = CreateInputPin<Numeric>();
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
|
||||
@ -18,7 +18,6 @@ public class RgbSKColorNode : Node
|
||||
#region Constructors
|
||||
|
||||
public RgbSKColorNode()
|
||||
: base("RGB Color", "Creates a color from red, green and blue values")
|
||||
{
|
||||
R = CreateInputPin<Numeric>("R");
|
||||
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))]
|
||||
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");
|
||||
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))]
|
||||
public class SaturateSKColorNode : Node
|
||||
{
|
||||
public SaturateSKColorNode() : base("Saturate Color", "Saturates a color by a specified amount in percent")
|
||||
public SaturateSKColorNode()
|
||||
{
|
||||
Input = CreateInputPin<SKColor>("Color");
|
||||
Percentage = CreateInputPin<Numeric>("%");
|
||||
|
||||
@ -9,8 +9,8 @@ public class SumSKColorsNode : Node
|
||||
#region Constructors
|
||||
|
||||
public SumSKColorsNode()
|
||||
: base("Sum", "Sums the connected color values.")
|
||||
{
|
||||
Name = "Sum";
|
||||
Values = CreateInputPinCollection<SKColor>("Values", 2);
|
||||
Sum = CreateOutputPin<SKColor>("Sum");
|
||||
}
|
||||
|
||||
@ -8,7 +8,6 @@ public class ConvertToNumericNode : Node
|
||||
#region Constructors
|
||||
|
||||
public ConvertToNumericNode()
|
||||
: base("To Numeric", "Converts the input to a numeric.")
|
||||
{
|
||||
Input = CreateInputPin<object>();
|
||||
Output = CreateOutputPin<Numeric>();
|
||||
|
||||
@ -2,13 +2,12 @@
|
||||
|
||||
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
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public ConvertToStringNode()
|
||||
: base("To String", "Converts the input to a string.")
|
||||
{
|
||||
Input = CreateInputPin<object>();
|
||||
String = CreateOutputPin<string>();
|
||||
|
||||
@ -15,7 +15,7 @@ public class DataModelEventCycleNode : Node<DataModelPathEntity, DataModelEventC
|
||||
private DateTime _lastTrigger;
|
||||
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);
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ public class DataModelEventNode : Node<DataModelPathEntity, DataModelEventNodeCu
|
||||
private OutputPin? _oldValuePin;
|
||||
private int _valueChangeCount;
|
||||
|
||||
public DataModelEventNode() : base("Data Model-Event", "Outputs the latest values of a data model event.")
|
||||
public DataModelEventNode()
|
||||
{
|
||||
_objectOutputPins = new ObjectOutputPins(this);
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ public class DataModelNode : Node<DataModelPathEntity, DataModelNodeCustomViewMo
|
||||
{
|
||||
private DataModelPath? _dataModelPath;
|
||||
|
||||
public DataModelNode() : base("Data Model", "Outputs a selectable data model value")
|
||||
public DataModelNode()
|
||||
{
|
||||
Output = CreateOutputPin(typeof(object));
|
||||
StorageModified += (_, _) => UpdateDataModelPath();
|
||||
|
||||
@ -6,7 +6,7 @@ namespace Artemis.VisualScripting.Nodes.Easing;
|
||||
[Node("Easing Type", "Outputs a selectable easing type.", "Easing", OutputType = typeof(Easings.Functions))]
|
||||
public class EasingTypeNode : Node<Easings.Functions, EasingTypeNodeCustomViewModel>
|
||||
{
|
||||
public EasingTypeNode() : base("Easing Type", "Outputs a selectable easing type.")
|
||||
public EasingTypeNode()
|
||||
{
|
||||
Output = CreateOutputPin<Easings.Functions>();
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ public class NumericEasingNode : Node
|
||||
private float _sourceValue;
|
||||
private float _targetValue;
|
||||
|
||||
public NumericEasingNode() : base("Numeric Easing", "Outputs an eased numeric value")
|
||||
public NumericEasingNode()
|
||||
{
|
||||
Input = CreateInputPin<Numeric>();
|
||||
EasingTime = CreateInputPin<Numeric>("delay");
|
||||
|
||||
@ -12,7 +12,7 @@ public class SKColorEasingNode : Node
|
||||
private SKColor _sourceValue;
|
||||
private SKColor _targetValue;
|
||||
|
||||
public SKColorEasingNode() : base("Color Easing", "Outputs an eased color value")
|
||||
public SKColorEasingNode()
|
||||
{
|
||||
Input = CreateInputPin<SKColor>();
|
||||
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))]
|
||||
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>();
|
||||
InputValue = CreateInputPin<object>();
|
||||
|
||||
@ -11,7 +11,7 @@ public class ListOperatorPredicateNode : Node<ListOperatorEntity, ListOperatorPr
|
||||
private readonly object _scriptLock = new();
|
||||
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};
|
||||
|
||||
|
||||
@ -19,7 +19,6 @@ public class ClampNode : Node
|
||||
#region Constructors
|
||||
|
||||
public ClampNode()
|
||||
: base("Clamp", "Clamps the value to be in between min and max")
|
||||
{
|
||||
Value = CreateInputPin<Numeric>("Value");
|
||||
Min = CreateInputPin<Numeric>("Min");
|
||||
|
||||
@ -9,7 +9,6 @@ public class CounterNode : Node
|
||||
private float _progress;
|
||||
|
||||
public CounterNode()
|
||||
: base("Counter", "Counts from 0.0 to 1.0 at a configurable rate.")
|
||||
{
|
||||
Time = CreateInputPin<Numeric>("Time (ms)");
|
||||
Output = CreateOutputPin<Numeric>();
|
||||
|
||||
@ -19,7 +19,6 @@ public class LerpNode : Node
|
||||
#region Constructors
|
||||
|
||||
public LerpNode()
|
||||
: base("Lerp", "Interpolates linear between the two values A and B")
|
||||
{
|
||||
A = CreateInputPin<Numeric>("A");
|
||||
B = CreateInputPin<Numeric>("B");
|
||||
|
||||
@ -5,7 +5,7 @@ using NoStringEvaluating.Models.FormulaChecker;
|
||||
|
||||
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>
|
||||
{
|
||||
private readonly IFormulaChecker _checker;
|
||||
@ -15,7 +15,6 @@ public class MathExpressionNode : Node<string, MathExpressionNodeCustomViewModel
|
||||
#region Constructors
|
||||
|
||||
public MathExpressionNode(INoStringEvaluator evaluator, IFormulaChecker checker)
|
||||
: base("Math Expression", "Outputs the result of a math expression.")
|
||||
{
|
||||
_evaluator = evaluator;
|
||||
_checker = checker;
|
||||
|
||||
@ -8,7 +8,6 @@ public class MaxNumericsNode : Node
|
||||
#region Constructors
|
||||
|
||||
public MaxNumericsNode()
|
||||
: base("Max", "Outputs the largest of the connected numeric values.")
|
||||
{
|
||||
Values = CreateInputPinCollection<Numeric>("Values", 2);
|
||||
Max = CreateOutputPin<Numeric>("Max");
|
||||
|
||||
@ -8,7 +8,6 @@ public class MinNumericsNode : Node
|
||||
#region Constructors
|
||||
|
||||
public MinNumericsNode()
|
||||
: base("Min", "Outputs the smallest of the connected numeric values.")
|
||||
{
|
||||
Values = CreateInputPinCollection<Numeric>("Values", 2);
|
||||
Min = CreateOutputPin<Numeric>("Min");
|
||||
|
||||
@ -19,7 +19,6 @@ public class RangeNode : Node
|
||||
#region Constructors
|
||||
|
||||
public RangeNode()
|
||||
: base("Range", "Selects the best integer value in the given range by the given percentage")
|
||||
{
|
||||
Min = CreateInputPin<Numeric>("Min");
|
||||
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))]
|
||||
public class RoundNode : Node
|
||||
{
|
||||
public RoundNode() : base("Round", "Outputs a rounded numeric value.")
|
||||
public RoundNode()
|
||||
{
|
||||
Input = CreateInputPin<Numeric>();
|
||||
Output = CreateOutputPin<Numeric>();
|
||||
|
||||
@ -17,7 +17,6 @@ public class SaturateNode : Node
|
||||
#region Constructors
|
||||
|
||||
public SaturateNode()
|
||||
: base("Saturate", "Clamps the value to be in between 0 and 1")
|
||||
{
|
||||
Value = CreateInputPin<Numeric>();
|
||||
|
||||
|
||||
@ -8,7 +8,6 @@ public class SumNumericsNode : Node
|
||||
#region Constructors
|
||||
|
||||
public SumNumericsNode()
|
||||
: base("Sum", "Sums the connected numeric values.")
|
||||
{
|
||||
Values = CreateInputPinCollection<Numeric>("Values", 2);
|
||||
Sum = CreateOutputPin<Numeric>("Sum");
|
||||
|
||||
@ -8,7 +8,6 @@ public class AndNode : Node
|
||||
#region Constructors
|
||||
|
||||
public AndNode()
|
||||
: base("And", "Checks if all inputs are true.")
|
||||
{
|
||||
Input = CreateInputPinCollection<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))]
|
||||
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>();
|
||||
OutputPin = CreateOutputPin<bool>();
|
||||
|
||||
@ -8,7 +8,6 @@ public class EqualsNode : Node
|
||||
#region Constructors
|
||||
|
||||
public EqualsNode()
|
||||
: base("Equals", "Checks if the two inputs are equals.")
|
||||
{
|
||||
Input1 = CreateInputPin<object>();
|
||||
Input2 = CreateInputPin<object>();
|
||||
|
||||
@ -9,7 +9,6 @@ public class GreaterThanNode : Node
|
||||
#region Constructors
|
||||
|
||||
public GreaterThanNode()
|
||||
: base("Greater than", "Checks if the first input is greater than the second.")
|
||||
{
|
||||
Input1 = CreateInputPin<object>();
|
||||
Input2 = CreateInputPin<object>();
|
||||
|
||||
@ -9,7 +9,6 @@ public class LessThanNode : Node
|
||||
#region Constructors
|
||||
|
||||
public LessThanNode()
|
||||
: base("Less than", "Checks if the first input is less than the second.")
|
||||
{
|
||||
Input1 = CreateInputPin<object>();
|
||||
Input2 = CreateInputPin<object>();
|
||||
|
||||
@ -8,7 +8,6 @@ public class NegateNode : Node
|
||||
#region Constructors
|
||||
|
||||
public NegateNode()
|
||||
: base("Negate", "Negates the boolean.")
|
||||
{
|
||||
Input = CreateInputPin<bool>();
|
||||
Output = CreateOutputPin<bool>();
|
||||
|
||||
@ -8,7 +8,6 @@ public class OrNode : Node
|
||||
#region Constructors
|
||||
|
||||
public OrNode()
|
||||
: base("Or", "Checks if any inputs are true.")
|
||||
{
|
||||
Input = CreateInputPinCollection<bool>();
|
||||
Result = CreateOutputPin<bool>();
|
||||
|
||||
@ -8,7 +8,6 @@ public class XorNode : Node
|
||||
#region Constructors
|
||||
|
||||
public XorNode()
|
||||
: base("Exclusive Or", "Checks if one of the inputs is true.")
|
||||
{
|
||||
Input = CreateInputPinCollection<bool>();
|
||||
Result = CreateOutputPin<bool>();
|
||||
|
||||
@ -6,7 +6,7 @@ namespace Artemis.VisualScripting.Nodes.Static;
|
||||
[Node("Display Value", "Displays an input value for testing purposes.", "Static", InputType = typeof(object))]
|
||||
public class DisplayValueNode : Node<string, DisplayValueNodeCustomViewModel>
|
||||
{
|
||||
public DisplayValueNode() : base("Display Value", "Displays an input value for testing purposes.")
|
||||
public DisplayValueNode()
|
||||
{
|
||||
Input = CreateInputPin<object>();
|
||||
}
|
||||
|
||||
@ -16,7 +16,6 @@ public class RandomNumericValueNode : Node
|
||||
#region Constructors
|
||||
|
||||
public RandomNumericValueNode()
|
||||
: base("Random", "Generates a random value between 0 and 1")
|
||||
{
|
||||
Output = CreateOutputPin<Numeric>();
|
||||
}
|
||||
|
||||
@ -9,8 +9,8 @@ public class StaticBooleanValueNode : Node<bool, StaticBooleanValueNodeCustomVie
|
||||
#region Constructors
|
||||
|
||||
public StaticBooleanValueNode()
|
||||
: base("Boolean", "Outputs a configurable static boolean value.")
|
||||
{
|
||||
Name = "Boolean";
|
||||
Output = CreateOutputPin<bool>();
|
||||
}
|
||||
|
||||
|
||||
@ -9,8 +9,8 @@ public class StaticNumericValueNode : Node<Numeric, StaticNumericValueNodeCustom
|
||||
#region Constructors
|
||||
|
||||
public StaticNumericValueNode()
|
||||
: base("Numeric", "Outputs a configurable numeric value.")
|
||||
{
|
||||
Name = "Numeric";
|
||||
Output = CreateOutputPin<Numeric>();
|
||||
}
|
||||
|
||||
|
||||
@ -10,8 +10,8 @@ public class StaticSKColorValueNode : Node<SKColor, StaticSKColorValueNodeCustom
|
||||
#region Constructors
|
||||
|
||||
public StaticSKColorValueNode()
|
||||
: base("Color", "Outputs a configurable color value.")
|
||||
{
|
||||
Name = "Color";
|
||||
Output = CreateOutputPin<SKColor>();
|
||||
Storage = new SKColor(255, 0, 0);
|
||||
}
|
||||
|
||||
@ -9,8 +9,8 @@ public class StaticStringValueNode : Node<string, StaticStringValueNodeCustomVie
|
||||
#region Constructors
|
||||
|
||||
public StaticStringValueNode()
|
||||
: base("Text", "Outputs a configurable text value.")
|
||||
{
|
||||
Name = "Text";
|
||||
Output = CreateOutputPin<string>();
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,6 @@ namespace Artemis.VisualScripting.Nodes.Text;
|
||||
public class StringContainsNode : Node
|
||||
{
|
||||
public StringContainsNode()
|
||||
: base("Contains", "Checks whether the first input is contained in the second input.")
|
||||
{
|
||||
Input1 = CreateInputPin<string>();
|
||||
Input2 = CreateInputPin<string>();
|
||||
|
||||
@ -8,7 +8,6 @@ public class StringFormatNode : Node
|
||||
#region Constructors
|
||||
|
||||
public StringFormatNode()
|
||||
: base("Format", "Formats the input string.")
|
||||
{
|
||||
Format = CreateInputPin<string>("Format");
|
||||
Values = CreateInputPinCollection<object>("Values");
|
||||
|
||||
@ -7,7 +7,6 @@ namespace Artemis.VisualScripting.Nodes.Text;
|
||||
public class StringLengthNode : Node
|
||||
{
|
||||
public StringLengthNode()
|
||||
: base("Text Length", "Outputs text length.")
|
||||
{
|
||||
Input1 = CreateInputPin<string>();
|
||||
Result = CreateOutputPin<Numeric>();
|
||||
|
||||
@ -7,7 +7,6 @@ namespace Artemis.VisualScripting.Nodes.Text;
|
||||
public class StringNullOrEmptyNode : Node
|
||||
{
|
||||
public StringNullOrEmptyNode()
|
||||
: base("Text is empty", "Outputs true if empty")
|
||||
{
|
||||
Input1 = CreateInputPin<string>();
|
||||
Output1 = CreateOutputPin<bool>();
|
||||
|
||||
@ -10,7 +10,7 @@ public class StringRegexMatchNode : Node
|
||||
private Regex? _regex;
|
||||
private Exception? _exception;
|
||||
|
||||
public StringRegexMatchNode() : base("Regex Match", "Checks provided regex pattern matches the input.")
|
||||
public StringRegexMatchNode()
|
||||
{
|
||||
Pattern = CreateInputPin<string>("Pattern");
|
||||
Input = CreateInputPin<string>("Input");
|
||||
|
||||
@ -25,7 +25,6 @@ public class DelayNode : Node
|
||||
#region Constructors
|
||||
|
||||
public DelayNode()
|
||||
: base("Delay", "Delays the resolution of the input pin(s) for the given time after each update")
|
||||
{
|
||||
Delay = CreateInputPin<Numeric>("Delay");
|
||||
Input = CreateInputPinCollection(typeof(object), initialCount: 0);
|
||||
|
||||
@ -17,7 +17,6 @@ public class EdgeNode : Node
|
||||
#region Constructors
|
||||
|
||||
public EdgeNode()
|
||||
: base("Edge", "Outputs true on each edge when the input changes")
|
||||
{
|
||||
Input = CreateInputPin<bool>();
|
||||
Output = CreateOutputPin<bool>();
|
||||
|
||||
@ -18,7 +18,6 @@ public class FlipFlopNode : Node
|
||||
#region Constructors
|
||||
|
||||
public FlipFlopNode()
|
||||
: base("FlipFlop", "Inverts the output when the input changes from false to true")
|
||||
{
|
||||
Input = CreateInputPin<bool>();
|
||||
Output = CreateOutputPin<bool>();
|
||||
|
||||
@ -25,7 +25,6 @@ public class LatchNode : Node
|
||||
#region Constructors
|
||||
|
||||
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");
|
||||
Input = CreateInputPinCollection(typeof(object), initialCount: 0);
|
||||
|
||||
@ -25,7 +25,6 @@ public class SequencerNode : Node
|
||||
#region Constructors
|
||||
|
||||
public SequencerNode()
|
||||
: base("Sequencer", "Advances on input every time the control has a rising edge (change to true)")
|
||||
{
|
||||
_currentType = typeof(object);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user