mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Nodes - Rewrote storage
This commit is contained in:
parent
3dfc25b092
commit
5b183d3010
@ -13,7 +13,7 @@ public class EventCondition : CorePropertyChanged, INodeScriptCondition
|
|||||||
{
|
{
|
||||||
private readonly string _displayName;
|
private readonly string _displayName;
|
||||||
private readonly EventConditionEntity _entity;
|
private readonly EventConditionEntity _entity;
|
||||||
private readonly EventDefaultNode _eventNode;
|
private EventDefaultNode _eventNode;
|
||||||
private DataModelPath? _eventPath;
|
private DataModelPath? _eventPath;
|
||||||
private DateTime _lastProcessedTrigger;
|
private DateTime _lastProcessedTrigger;
|
||||||
private EventOverlapMode _overlapMode;
|
private EventOverlapMode _overlapMode;
|
||||||
@ -199,6 +199,7 @@ public class EventCondition : CorePropertyChanged, INodeScriptCondition
|
|||||||
Script = _entity.Script != null
|
Script = _entity.Script != null
|
||||||
? new NodeScript<bool>($"Activate {_displayName}", $"Whether or not the event should activate the {_displayName}", _entity.Script, ProfileElement.Profile)
|
? new NodeScript<bool>($"Activate {_displayName}", $"Whether or not the event should activate the {_displayName}", _entity.Script, ProfileElement.Profile)
|
||||||
: new NodeScript<bool>($"Activate {_displayName}", $"Whether or not the event should activate the {_displayName}", ProfileElement.Profile);
|
: new NodeScript<bool>($"Activate {_displayName}", $"Whether or not the event should activate the {_displayName}", ProfileElement.Profile);
|
||||||
|
UpdateEventNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -219,8 +220,15 @@ public class EventCondition : CorePropertyChanged, INodeScriptCondition
|
|||||||
public void LoadNodeScript()
|
public void LoadNodeScript()
|
||||||
{
|
{
|
||||||
Script.Load();
|
Script.Load();
|
||||||
|
|
||||||
|
// The load action may have created an event node, use that one over the one we have here
|
||||||
|
INode? existingEventNode = Script.Nodes.FirstOrDefault(n => n.Id == EventDefaultNode.NodeId);
|
||||||
|
if (existingEventNode != null)
|
||||||
|
_eventNode = (EventDefaultNode) existingEventNode;
|
||||||
|
|
||||||
UpdateEventNode();
|
UpdateEventNode();
|
||||||
Script.LoadConnections();
|
Script.LoadConnections();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -253,13 +261,13 @@ public enum EventOverlapMode
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Restart,
|
Restart,
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ignore subsequent event fires until the timeline finishes
|
|
||||||
/// </summary>
|
|
||||||
Ignore,
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Play another copy of the timeline on top of the current run
|
/// Play another copy of the timeline on top of the current run
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Copy
|
Copy,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ignore subsequent event fires until the timeline finishes
|
||||||
|
/// </summary>
|
||||||
|
Ignore
|
||||||
}
|
}
|
||||||
@ -72,6 +72,30 @@ namespace Artemis.Core
|
|||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="Layer" /> class by copying the provided <paramref name="source"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">The layer to copy</param>
|
||||||
|
/// <param name="parent">The parent of the layer</param>
|
||||||
|
public Layer(Layer source, ProfileElement parent) : base(parent, parent.Profile)
|
||||||
|
{
|
||||||
|
LayerEntity = CoreJson.DeserializeObject<LayerEntity>(CoreJson.SerializeObject(source.LayerEntity, true), true) ?? new LayerEntity();
|
||||||
|
LayerEntity.Id = Guid.NewGuid();
|
||||||
|
|
||||||
|
Profile = source.Profile;
|
||||||
|
Parent = parent;
|
||||||
|
|
||||||
|
_general = new LayerGeneralProperties();
|
||||||
|
_transform = new LayerTransformProperties();
|
||||||
|
|
||||||
|
_leds = new List<ArtemisLed>();
|
||||||
|
Leds = new ReadOnlyCollection<ArtemisLed>(_leds);
|
||||||
|
|
||||||
|
Adapter = new LayerAdapter(this);
|
||||||
|
Load();
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A collection of all the LEDs this layer is assigned to.
|
/// A collection of all the LEDs this layer is assigned to.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -349,7 +373,7 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
if (ShouldBeEnabled)
|
if (ShouldBeEnabled)
|
||||||
Enable();
|
Enable();
|
||||||
else if (Timeline.IsFinished)
|
else if (Timeline.IsFinished && !Children.Any())
|
||||||
Disable();
|
Disable();
|
||||||
|
|
||||||
if (Timeline.Delta == TimeSpan.Zero)
|
if (Timeline.Delta == TimeSpan.Zero)
|
||||||
@ -365,15 +389,16 @@ namespace Artemis.Core
|
|||||||
// Remove children that finished their timeline and update the rest
|
// Remove children that finished their timeline and update the rest
|
||||||
for (int index = 0; index < Children.Count; index++)
|
for (int index = 0; index < Children.Count; index++)
|
||||||
{
|
{
|
||||||
ProfileElement profileElement = Children[index];
|
Layer child = (Layer) Children[index];
|
||||||
if (((Layer) profileElement).Timeline.IsFinished)
|
if (!child.Timeline.IsFinished)
|
||||||
{
|
{
|
||||||
RemoveChild(profileElement);
|
child.Update(deltaTime);
|
||||||
profileElement.Dispose();
|
continue;
|
||||||
index--;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
profileElement.Update(deltaTime);
|
RemoveChild(child);
|
||||||
|
child.Dispose();
|
||||||
|
index--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,6 +408,12 @@ namespace Artemis.Core
|
|||||||
if (Disposed)
|
if (Disposed)
|
||||||
throw new ObjectDisposedException("Layer");
|
throw new ObjectDisposedException("Layer");
|
||||||
|
|
||||||
|
RenderSelf(canvas, basePosition);
|
||||||
|
RenderChildren(canvas, basePosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenderSelf(SKCanvas canvas, SKPointI basePosition)
|
||||||
|
{
|
||||||
// Ensure the layer is ready
|
// Ensure the layer is ready
|
||||||
if (!Enabled || Path == null || LayerShape?.Path == null || !General.PropertiesInitialized || !Transform.PropertiesInitialized || !Leds.Any())
|
if (!Enabled || Path == null || LayerShape?.Path == null || !General.PropertiesInitialized || !Transform.PropertiesInitialized || !Leds.Any())
|
||||||
return;
|
return;
|
||||||
@ -454,6 +485,13 @@ namespace Artemis.Core
|
|||||||
Timeline.ClearDelta();
|
Timeline.ClearDelta();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RenderChildren(SKCanvas canvas, SKPointI basePosition)
|
||||||
|
{
|
||||||
|
// Render children first so they go below
|
||||||
|
for (int i = Children.Count - 1; i >= 0; i--)
|
||||||
|
Children[i].Render(canvas, basePosition);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Enable()
|
public override void Enable()
|
||||||
{
|
{
|
||||||
@ -523,11 +561,11 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void CreateCopyAsChild()
|
public void CreateCopyAsChild()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
Layer copy = new(this, this);
|
||||||
|
copy.AddLeds(Leds);
|
||||||
// Create a copy of the layer and it's properties
|
copy.Enable();
|
||||||
|
copy.Timeline.JumpToStart();
|
||||||
// Add to children
|
AddChild(copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void CalculateRenderProperties()
|
internal void CalculateRenderProperties()
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Artemis.Storage.Entities.Profile.Nodes;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace Artemis.Core
|
namespace Artemis.Core
|
||||||
@ -51,11 +52,11 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NodeTypeRegistration? Get(Guid pluginGuid, string type)
|
public static NodeTypeRegistration? Get(NodeEntity entity)
|
||||||
{
|
{
|
||||||
lock (Registrations)
|
lock (Registrations)
|
||||||
{
|
{
|
||||||
return Registrations.FirstOrDefault(r => r.Plugin.Guid == pluginGuid && r.NodeData.Type.Name == type);
|
return Registrations.FirstOrDefault(r => r.MatchesEntity(entity));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using Artemis.Storage.Entities.Profile.Nodes;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace Artemis.Core
|
namespace Artemis.Core
|
||||||
@ -37,6 +38,16 @@ namespace Artemis.Core
|
|||||||
if (IsInStore)
|
if (IsInStore)
|
||||||
NodeTypeStore.Remove(this);
|
NodeTypeStore.Remove(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the provided entity matches this node type registration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entity">The entity to check.</param>
|
||||||
|
/// <returns><see langword="true"/> if the entity matches this registration; otherwise <see langword="false"/>.</returns>
|
||||||
|
public bool MatchesEntity(NodeEntity entity)
|
||||||
|
{
|
||||||
|
return Plugin.Guid == entity.PluginId && NodeData.Type.Name == entity.Type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -9,6 +9,11 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface INode : INotifyPropertyChanged
|
public interface INode : INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the ID of the node.
|
||||||
|
/// </summary>
|
||||||
|
Guid Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the name of the node
|
/// Gets the name of the node
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -59,6 +59,9 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes a node from the script
|
/// Removes a node from the script
|
||||||
|
/// <para>
|
||||||
|
/// Note: If the node is <see cref="IDisposable"/> you must dispose it yourself, unless you plan to reuse the node.
|
||||||
|
/// </para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="node">The node to remove</param>
|
/// <param name="node">The node to remove</param>
|
||||||
void RemoveNode(INode node);
|
void RemoveNode(INode node);
|
||||||
|
|||||||
36
src/Artemis.Core/VisualScripting/Internal/DefaultNode.cs
Normal file
36
src/Artemis.Core/VisualScripting/Internal/DefaultNode.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Artemis.Core.Internal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a kind of node that cannot be deleted inside a <see cref="INode" />.
|
||||||
|
/// </summary>
|
||||||
|
public interface IDefaultNode : INode
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a kind of node that cannot be deleted inside a <see cref="NodeScript" />.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class DefaultNode : Node, IDefaultNode
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool IsDefaultNode => true;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected DefaultNode(Guid id, string name, string description = "") : base(name, description)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
Name = name;
|
||||||
|
Description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,19 +7,18 @@ using Humanizer;
|
|||||||
|
|
||||||
namespace Artemis.Core.Internal
|
namespace Artemis.Core.Internal
|
||||||
{
|
{
|
||||||
internal class EventDefaultNode : Node
|
internal class EventDefaultNode : DefaultNode
|
||||||
{
|
{
|
||||||
|
internal static readonly Guid NodeId = new("278735FE-69E9-4A73-A6B8-59E83EE19305");
|
||||||
private readonly Dictionary<PropertyInfo, OutputPin> _propertyPins;
|
private readonly Dictionary<PropertyInfo, OutputPin> _propertyPins;
|
||||||
private readonly List<OutputPin> _pinBucket = new();
|
private readonly List<OutputPin> _pinBucket = new();
|
||||||
private IDataModelEvent? _dataModelEvent;
|
private IDataModelEvent? _dataModelEvent;
|
||||||
|
|
||||||
public EventDefaultNode() : base("Event Arguments", "Contains the event arguments that triggered the evaluation")
|
public EventDefaultNode() : base(NodeId, "Event Arguments", "Contains the event arguments that triggered the evaluation")
|
||||||
{
|
{
|
||||||
_propertyPins = new Dictionary<PropertyInfo, OutputPin>();
|
_propertyPins = new Dictionary<PropertyInfo, OutputPin>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsDefaultNode => true;
|
|
||||||
|
|
||||||
public void CreatePins(IDataModelEvent? dataModelEvent)
|
public void CreatePins(IDataModelEvent? dataModelEvent)
|
||||||
{
|
{
|
||||||
if (_dataModelEvent == dataModelEvent)
|
if (_dataModelEvent == dataModelEvent)
|
||||||
@ -33,9 +32,12 @@ namespace Artemis.Core.Internal
|
|||||||
if (dataModelEvent == null)
|
if (dataModelEvent == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (PropertyInfo propertyInfo in dataModelEvent.ArgumentsType.GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
foreach (PropertyInfo propertyInfo in dataModelEvent.ArgumentsType
|
||||||
|
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||||
.Where(p => p.CustomAttributes.All(a => a.AttributeType != typeof(DataModelIgnoreAttribute))))
|
.Where(p => p.CustomAttributes.All(a => a.AttributeType != typeof(DataModelIgnoreAttribute))))
|
||||||
|
{
|
||||||
_propertyPins.Add(propertyInfo, CreateOrAddOutputPin(propertyInfo.PropertyType, propertyInfo.Name.Humanize()));
|
_propertyPins.Add(propertyInfo, CreateOrAddOutputPin(propertyInfo.PropertyType, propertyInfo.Name.Humanize()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Evaluate()
|
public override void Evaluate()
|
||||||
|
|||||||
@ -1,12 +1,16 @@
|
|||||||
namespace Artemis.Core.Internal
|
using System;
|
||||||
|
|
||||||
|
namespace Artemis.Core.Internal
|
||||||
{
|
{
|
||||||
internal interface IExitNode : INode
|
internal interface IExitNode : INode
|
||||||
{ }
|
{
|
||||||
|
protected static readonly Guid NodeId = new("410C824D-C5E3-4E3A-8080-D50F6C8B83B8");
|
||||||
|
}
|
||||||
|
|
||||||
internal class ExitNode<T> : Node, IExitNode
|
internal class ExitNode<T> : Node, IExitNode
|
||||||
{
|
{
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
|
|
||||||
public InputPin<T> Input { get; }
|
public InputPin<T> Input { get; }
|
||||||
|
|
||||||
public T? Value { get; private set; }
|
public T? Value { get; private set; }
|
||||||
@ -19,6 +23,7 @@
|
|||||||
|
|
||||||
public ExitNode(string name, string description = "")
|
public ExitNode(string name, string description = "")
|
||||||
{
|
{
|
||||||
|
Id = IExitNode.NodeId;
|
||||||
Name = name;
|
Name = name;
|
||||||
Description = description;
|
Description = description;
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using Artemis.Core.Properties;
|
|
||||||
using Ninject;
|
using Ninject;
|
||||||
using Ninject.Parameters;
|
using Ninject.Parameters;
|
||||||
|
|
||||||
@ -16,6 +15,15 @@ public abstract class Node : CorePropertyChanged, INode
|
|||||||
public event EventHandler? Resetting;
|
public event EventHandler? Resetting;
|
||||||
|
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private Guid _id;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Guid Id
|
||||||
|
{
|
||||||
|
get => _id;
|
||||||
|
set => SetAndNotify(ref _id , value);
|
||||||
|
}
|
||||||
|
|
||||||
private string _name;
|
private string _name;
|
||||||
|
|
||||||
@ -65,7 +73,7 @@ public abstract class Node : CorePropertyChanged, 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();
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IReadOnlyCollection<IPinCollection> PinCollections => new ReadOnlyCollection<IPinCollection>(_pinCollections);
|
public IReadOnlyCollection<IPinCollection> PinCollections => new ReadOnlyCollection<IPinCollection>(_pinCollections);
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,9 @@ namespace Artemis.Core
|
|||||||
{
|
{
|
||||||
private void NodeTypeStoreOnNodeTypeChanged(object? sender, NodeTypeStoreEvent e)
|
private void NodeTypeStoreOnNodeTypeChanged(object? sender, NodeTypeStoreEvent e)
|
||||||
{
|
{
|
||||||
Load();
|
// Only respond to node changes applicable to the current script
|
||||||
|
if (Entity.Nodes.Any(n => e.TypeRegistration.MatchesEntity(n)))
|
||||||
|
Load();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -153,41 +155,38 @@ namespace Artemis.Core
|
|||||||
{
|
{
|
||||||
lock (_nodes)
|
lock (_nodes)
|
||||||
{
|
{
|
||||||
List<INode> removeNodes = _nodes.Where(n => !n.IsExitNode).ToList();
|
// Remove nodes no longer on the entity
|
||||||
|
List<INode> removeNodes = _nodes.Where(n => Entity.Nodes.All(e => e.Id != n.Id)).ToList();
|
||||||
foreach (INode removeNode in removeNodes)
|
foreach (INode removeNode in removeNodes)
|
||||||
|
{
|
||||||
RemoveNode(removeNode);
|
RemoveNode(removeNode);
|
||||||
|
if (removeNode is IDisposable disposable)
|
||||||
|
disposable.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create nodes
|
// Create missing nodes nodes
|
||||||
foreach (NodeEntity entityNode in Entity.Nodes)
|
foreach (NodeEntity nodeEntity in Entity.Nodes)
|
||||||
{
|
{
|
||||||
INode? node = LoadNode(entityNode, entityNode.IsExitNode ? ExitNode : null);
|
INode? node = Nodes.FirstOrDefault(n => n.Id == nodeEntity.Id);
|
||||||
if (node == null)
|
// If the node already exists, apply the entity to it
|
||||||
continue;
|
if (node != null)
|
||||||
|
LoadExistingNode(node, nodeEntity);
|
||||||
if (!entityNode.IsExitNode)
|
else
|
||||||
AddNode(node);
|
{
|
||||||
|
INode? loaded = LoadNode(nodeEntity);
|
||||||
|
if (loaded != null)
|
||||||
|
AddNode(loaded);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadConnections();
|
LoadConnections();
|
||||||
}
|
}
|
||||||
|
|
||||||
private INode? LoadNode(NodeEntity nodeEntity, INode? node)
|
private void LoadExistingNode(INode node, NodeEntity nodeEntity)
|
||||||
{
|
{
|
||||||
if (node == null)
|
node.X = nodeEntity.X;
|
||||||
{
|
node.Y = nodeEntity.Y;
|
||||||
NodeTypeRegistration? nodeTypeRegistration = NodeTypeStore.Get(nodeEntity.PluginId, nodeEntity.Type);
|
|
||||||
if (nodeTypeRegistration == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// Create the node
|
|
||||||
node = nodeTypeRegistration.NodeData.CreateNode(this, nodeEntity);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node.X = nodeEntity.X;
|
|
||||||
node.Y = nodeEntity.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore pin collections
|
// Restore pin collections
|
||||||
foreach (NodePinCollectionEntity entityNodePinCollection in nodeEntity.PinCollections)
|
foreach (NodePinCollectionEntity entityNodePinCollection in nodeEntity.PinCollections)
|
||||||
@ -201,7 +200,17 @@ namespace Artemis.Core
|
|||||||
while (collection.Count() < entityNodePinCollection.Amount)
|
while (collection.Count() < entityNodePinCollection.Amount)
|
||||||
collection.Add(collection.CreatePin());
|
collection.Add(collection.CreatePin());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private INode? LoadNode(NodeEntity nodeEntity)
|
||||||
|
{
|
||||||
|
NodeTypeRegistration? nodeTypeRegistration = NodeTypeStore.Get(nodeEntity);
|
||||||
|
if (nodeTypeRegistration == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Create the node
|
||||||
|
INode node = nodeTypeRegistration.NodeData.CreateNode(this, nodeEntity);
|
||||||
|
LoadExistingNode(node, nodeEntity);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,10 +222,10 @@ namespace Artemis.Core
|
|||||||
List<INode> nodes = Nodes.ToList();
|
List<INode> nodes = Nodes.ToList();
|
||||||
foreach (NodeConnectionEntity nodeConnectionEntity in Entity.Connections.OrderBy(p => p.SourcePinCollectionId))
|
foreach (NodeConnectionEntity nodeConnectionEntity in Entity.Connections.OrderBy(p => p.SourcePinCollectionId))
|
||||||
{
|
{
|
||||||
INode? source = nodes.ElementAtOrDefault(nodeConnectionEntity.SourceNode);
|
INode? source = nodes.FirstOrDefault(n => n.Id == nodeConnectionEntity.SourceNode);
|
||||||
if (source == null)
|
if (source == null)
|
||||||
continue;
|
continue;
|
||||||
INode? target = nodes.ElementAtOrDefault(nodeConnectionEntity.TargetNode);
|
INode? target = nodes.FirstOrDefault(n => n.Id == nodeConnectionEntity.TargetNode);
|
||||||
if (target == null)
|
if (target == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -263,12 +272,11 @@ namespace Artemis.Core
|
|||||||
if (Nodes.Count() == 1)
|
if (Nodes.Count() == 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int id = 0;
|
|
||||||
foreach (INode node in Nodes)
|
foreach (INode node in Nodes)
|
||||||
{
|
{
|
||||||
NodeEntity nodeEntity = new()
|
NodeEntity nodeEntity = new()
|
||||||
{
|
{
|
||||||
Id = id,
|
Id = node.Id,
|
||||||
PluginId = NodeTypeStore.GetPlugin(node)?.Guid ?? Constants.CorePlugin.Guid,
|
PluginId = NodeTypeStore.GetPlugin(node)?.Guid ?? Constants.CorePlugin.Guid,
|
||||||
Type = node.GetType().Name,
|
Type = node.GetType().Name,
|
||||||
X = node.X,
|
X = node.X,
|
||||||
@ -294,7 +302,6 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
Entity.Nodes.Add(nodeEntity);
|
Entity.Nodes.Add(nodeEntity);
|
||||||
id++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store connections
|
// Store connections
|
||||||
@ -315,7 +322,6 @@ namespace Artemis.Core
|
|||||||
private void SavePins(INode node, int collectionId, IEnumerable<IPin> pins)
|
private void SavePins(INode node, int collectionId, IEnumerable<IPin> pins)
|
||||||
{
|
{
|
||||||
int sourcePinId = 0;
|
int sourcePinId = 0;
|
||||||
List<INode> nodes = Nodes.ToList();
|
|
||||||
foreach (IPin sourcePin in pins.Where(p => p.Direction == PinDirection.Input))
|
foreach (IPin sourcePin in pins.Where(p => p.Direction == PinDirection.Input))
|
||||||
{
|
{
|
||||||
foreach (IPin targetPin in sourcePin.ConnectedTo)
|
foreach (IPin targetPin in sourcePin.ConnectedTo)
|
||||||
@ -337,11 +343,11 @@ namespace Artemis.Core
|
|||||||
Entity.Connections.Add(new NodeConnectionEntity
|
Entity.Connections.Add(new NodeConnectionEntity
|
||||||
{
|
{
|
||||||
SourceType = sourcePin.Type.Name,
|
SourceType = sourcePin.Type.Name,
|
||||||
SourceNode = nodes.IndexOf(node),
|
SourceNode = node.Id,
|
||||||
SourcePinCollectionId = collectionId,
|
SourcePinCollectionId = collectionId,
|
||||||
SourcePinId = sourcePinId,
|
SourcePinId = sourcePinId,
|
||||||
TargetType = targetPin.Type.Name,
|
TargetType = targetPin.Type.Name,
|
||||||
TargetNode = nodes.IndexOf(targetPin.Node),
|
TargetNode = targetPin.Node.Id,
|
||||||
TargetPinCollectionId = targetPinCollectionId,
|
TargetPinCollectionId = targetPinCollectionId,
|
||||||
TargetPinId = targetPinId
|
TargetPinId = targetPinId
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
namespace Artemis.Storage.Entities.Profile.Nodes
|
using System;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Entities.Profile.Nodes
|
||||||
{
|
{
|
||||||
public class NodeConnectionEntity
|
public class NodeConnectionEntity
|
||||||
{
|
{
|
||||||
public string SourceType { get; set; }
|
public string SourceType { get; set; }
|
||||||
public int SourceNode { get; set; }
|
public Guid SourceNode { get; set; }
|
||||||
public int TargetNode { get; set; }
|
public Guid TargetNode { get; set; }
|
||||||
public int SourcePinCollectionId { get; set; }
|
public int SourcePinCollectionId { get; set; }
|
||||||
public int SourcePinId { get; set; }
|
public int SourcePinId { get; set; }
|
||||||
public string TargetType { get; set; }
|
public string TargetType { get; set; }
|
||||||
|
|||||||
@ -10,7 +10,7 @@ namespace Artemis.Storage.Entities.Profile.Nodes
|
|||||||
PinCollections = new List<NodePinCollectionEntity>();
|
PinCollections = new List<NodePinCollectionEntity>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int 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; }
|
||||||
|
|
||||||
|
|||||||
@ -39,7 +39,8 @@
|
|||||||
<TextBlock Name="MainButtonLabel"
|
<TextBlock Name="MainButtonLabel"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
TextAlignment="Left" />
|
TextAlignment="Left"
|
||||||
|
TextTrimming="CharacterEllipsis"/>
|
||||||
<TextBlock Name="ChevronTextBlock"
|
<TextBlock Name="ChevronTextBlock"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
FontFamily="{DynamicResource SymbolThemeFontFamily}"
|
FontFamily="{DynamicResource SymbolThemeFontFamily}"
|
||||||
|
|||||||
@ -18,7 +18,8 @@
|
|||||||
DockPanel.Dock="Top"
|
DockPanel.Dock="Top"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
FilterTypes="{CompiledBinding FilterTypes}"
|
FilterTypes="{CompiledBinding FilterTypes}"
|
||||||
DataModelPath="{CompiledBinding EventPath}"/>
|
DataModelPath="{CompiledBinding EventPath}"
|
||||||
|
ShowFullPath="{CompiledBinding ShowFullPaths.Value}"/>
|
||||||
|
|
||||||
<TextBlock DockPanel.Dock="Top">When the event fires..</TextBlock>
|
<TextBlock DockPanel.Dock="Top">When the event fires..</TextBlock>
|
||||||
<ComboBox PlaceholderText="Select a play mode" HorizontalAlignment="Stretch" DockPanel.Dock="Top" SelectedIndex="{CompiledBinding SelectedTriggerMode}">
|
<ComboBox PlaceholderText="Select a play mode" HorizontalAlignment="Stretch" DockPanel.Dock="Top" SelectedIndex="{CompiledBinding SelectedTriggerMode}">
|
||||||
|
|||||||
@ -4,6 +4,7 @@ using System.Reactive;
|
|||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.Screens.VisualScripting;
|
using Artemis.UI.Screens.VisualScripting;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
@ -20,15 +21,17 @@ public class EventConditionViewModel : ActivatableViewModelBase
|
|||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private readonly ObservableAsPropertyHelper<bool> _showOverlapOptions;
|
private readonly ObservableAsPropertyHelper<bool> _showOverlapOptions;
|
||||||
private readonly IWindowService _windowService;
|
private readonly IWindowService _windowService;
|
||||||
|
private readonly ISettingsService _settingsService;
|
||||||
private ObservableAsPropertyHelper<DataModelPath?>? _eventPath;
|
private ObservableAsPropertyHelper<DataModelPath?>? _eventPath;
|
||||||
private ObservableAsPropertyHelper<int>? _selectedOverlapMode;
|
private ObservableAsPropertyHelper<int>? _selectedOverlapMode;
|
||||||
private ObservableAsPropertyHelper<int>? _selectedTriggerMode;
|
private ObservableAsPropertyHelper<int>? _selectedTriggerMode;
|
||||||
|
|
||||||
public EventConditionViewModel(EventCondition eventCondition, IProfileEditorService profileEditorService, IWindowService windowService)
|
public EventConditionViewModel(EventCondition eventCondition, IProfileEditorService profileEditorService, IWindowService windowService, ISettingsService settingsService)
|
||||||
{
|
{
|
||||||
_eventCondition = eventCondition;
|
_eventCondition = eventCondition;
|
||||||
_profileEditorService = profileEditorService;
|
_profileEditorService = profileEditorService;
|
||||||
_windowService = windowService;
|
_windowService = windowService;
|
||||||
|
_settingsService = settingsService;
|
||||||
_showOverlapOptions = this.WhenAnyValue(vm => vm.SelectedTriggerMode)
|
_showOverlapOptions = this.WhenAnyValue(vm => vm.SelectedTriggerMode)
|
||||||
.Select(m => m == 0)
|
.Select(m => m == 0)
|
||||||
.ToProperty(this, vm => vm.ShowOverlapOptions);
|
.ToProperty(this, vm => vm.ShowOverlapOptions);
|
||||||
@ -47,6 +50,7 @@ public class EventConditionViewModel : ActivatableViewModelBase
|
|||||||
public ReactiveCommand<Unit, Unit> OpenEditor { get; }
|
public ReactiveCommand<Unit, Unit> OpenEditor { get; }
|
||||||
public bool ShowOverlapOptions => _showOverlapOptions.Value;
|
public bool ShowOverlapOptions => _showOverlapOptions.Value;
|
||||||
public bool IsConditionForLayer => _eventCondition.ProfileElement is Layer;
|
public bool IsConditionForLayer => _eventCondition.ProfileElement is Layer;
|
||||||
|
public PluginSetting<bool> ShowFullPaths => _settingsService.GetSetting("ProfileEditor.ShowFullPaths", false);
|
||||||
|
|
||||||
public DataModelPath? EventPath
|
public DataModelPath? EventPath
|
||||||
{
|
{
|
||||||
|
|||||||
@ -128,40 +128,41 @@
|
|||||||
<MenuItem Header="_Options">
|
<MenuItem Header="_Options">
|
||||||
<MenuItem Header="Focus Selected Layer"
|
<MenuItem Header="Focus Selected Layer"
|
||||||
ToolTip.Tip="If enabled, displays only the layer you currently have selected"
|
ToolTip.Tip="If enabled, displays only the layer you currently have selected"
|
||||||
IsEnabled="False">
|
Command="{CompiledBinding ToggleBooleanSetting}"
|
||||||
|
CommandParameter="{CompiledBinding FocusSelectedLayer}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<CheckBox BorderThickness="0"
|
<avalonia:MaterialIcon Kind="Check" IsVisible="{CompiledBinding FocusSelectedLayer.Value}"></avalonia:MaterialIcon>
|
||||||
IsHitTestVisible="False"
|
</MenuItem.Icon>
|
||||||
IsChecked="{Binding FocusSelectedLayer.Value}" />
|
|
||||||
</MenuItem.Icon>
|
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Display Data Model Values">
|
<MenuItem Header="Display Data Model Values"
|
||||||
<MenuItem.Icon>
|
Command="{CompiledBinding ToggleBooleanSetting}"
|
||||||
<CheckBox BorderThickness="0"
|
CommandParameter="{CompiledBinding ShowDataModelValues}">
|
||||||
IsHitTestVisible="False"
|
<MenuItem.Icon>
|
||||||
IsChecked="{Binding ShowDataModelValues.Value}" />
|
<avalonia:MaterialIcon Kind="Check" IsVisible="{CompiledBinding ShowDataModelValues.Value}"></avalonia:MaterialIcon>
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Display Full Condition Paths">
|
<MenuItem Header="Display Full Condition Paths"
|
||||||
<MenuItem.Icon>
|
Command="{CompiledBinding ToggleBooleanSetting}"
|
||||||
<CheckBox BorderThickness="0"
|
CommandParameter="{CompiledBinding ShowFullPaths}">
|
||||||
IsHitTestVisible="False"
|
<MenuItem.Icon>
|
||||||
IsChecked="{Binding ShowFullPaths.Value}" />
|
<avalonia:MaterialIcon Kind="Check" IsVisible="{CompiledBinding ShowFullPaths.Value}"></avalonia:MaterialIcon>
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Always Display Cable Values" ToolTip.Tip="If enabled, cable values are always shown instead of only on hover">
|
<MenuItem Header="Always Display Cable Values"
|
||||||
<MenuItem.Icon>
|
ToolTip.Tip="If enabled, cable values are always shown instead of only on hover"
|
||||||
<CheckBox BorderThickness="0"
|
Command="{CompiledBinding ToggleBooleanSetting}"
|
||||||
IsHitTestVisible="False"
|
CommandParameter="{CompiledBinding AlwaysShowValues}">
|
||||||
IsChecked="{Binding AlwaysShowValues.Value}" />
|
<MenuItem.Icon>
|
||||||
</MenuItem.Icon>
|
<avalonia:MaterialIcon Kind="Check" IsVisible="{CompiledBinding AlwaysShowValues.Value}"></avalonia:MaterialIcon>
|
||||||
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Apply All Data Bindings During Edit" ToolTip.Tip="If enabled, updates all data bindings instead of only the one you are editing">
|
<MenuItem Header="Apply All Data Bindings During Edit"
|
||||||
<MenuItem.Icon>
|
ToolTip.Tip="If enabled, updates all data bindings instead of only the one you are editing"
|
||||||
<CheckBox BorderThickness="0"
|
Command="{CompiledBinding ToggleBooleanSetting}"
|
||||||
IsHitTestVisible="False"
|
CommandParameter="{CompiledBinding AlwaysApplyDataBindings}">
|
||||||
IsChecked="{Binding AlwaysApplyDataBindings.Value}" />
|
<MenuItem.Icon>
|
||||||
</MenuItem.Icon>
|
<avalonia:MaterialIcon Kind="Check" IsVisible="{CompiledBinding AlwaysApplyDataBindings.Value}"></avalonia:MaterialIcon>
|
||||||
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="_Help">
|
<MenuItem Header="_Help">
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Reactive;
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
@ -12,13 +13,15 @@ namespace Artemis.UI.Screens.ProfileEditor.MenuBar;
|
|||||||
public class MenuBarViewModel : ActivatableViewModelBase
|
public class MenuBarViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly IProfileService _profileService;
|
private readonly IProfileService _profileService;
|
||||||
|
private readonly ISettingsService _settingsService;
|
||||||
private ProfileEditorHistory? _history;
|
private ProfileEditorHistory? _history;
|
||||||
private ObservableAsPropertyHelper<ProfileConfiguration?>? _profileConfiguration;
|
private ObservableAsPropertyHelper<ProfileConfiguration?>? _profileConfiguration;
|
||||||
private ObservableAsPropertyHelper<bool>? _isSuspended;
|
private ObservableAsPropertyHelper<bool>? _isSuspended;
|
||||||
|
|
||||||
public MenuBarViewModel(IProfileEditorService profileEditorService, IProfileService profileService)
|
public MenuBarViewModel(IProfileEditorService profileEditorService, IProfileService profileService, ISettingsService settingsService)
|
||||||
{
|
{
|
||||||
_profileService = profileService;
|
_profileService = profileService;
|
||||||
|
_settingsService = settingsService;
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
profileEditorService.History.Subscribe(history => History = history).DisposeWith(d);
|
profileEditorService.History.Subscribe(history => History = history).DisposeWith(d);
|
||||||
@ -29,16 +32,30 @@ public class MenuBarViewModel : ActivatableViewModelBase
|
|||||||
.ToProperty(this, vm => vm.IsSuspended)
|
.ToProperty(this, vm => vm.IsSuspended)
|
||||||
.DisposeWith(d);
|
.DisposeWith(d);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ToggleBooleanSetting = ReactiveCommand.Create<PluginSetting<bool>>(ExecuteToggleBooleanSetting);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ExecuteToggleBooleanSetting(PluginSetting<bool> setting)
|
||||||
|
{
|
||||||
|
setting.Value = !setting.Value;
|
||||||
|
setting.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReactiveCommand<PluginSetting<bool>, Unit> ToggleBooleanSetting { get; }
|
||||||
|
public ProfileConfiguration? ProfileConfiguration => _profileConfiguration?.Value;
|
||||||
|
public PluginSetting<bool> FocusSelectedLayer => _settingsService.GetSetting("ProfileEditor.FocusSelectedLayer", false);
|
||||||
|
public PluginSetting<bool> ShowDataModelValues => _settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false);
|
||||||
|
public PluginSetting<bool> ShowFullPaths => _settingsService.GetSetting("ProfileEditor.ShowFullPaths", false);
|
||||||
|
public PluginSetting<bool> AlwaysShowValues => _settingsService.GetSetting("ProfileEditor.AlwaysShowValues", false);
|
||||||
|
public PluginSetting<bool> AlwaysApplyDataBindings => _settingsService.GetSetting("ProfileEditor.AlwaysApplyDataBindings", false);
|
||||||
|
|
||||||
public ProfileEditorHistory? History
|
public ProfileEditorHistory? History
|
||||||
{
|
{
|
||||||
get => _history;
|
get => _history;
|
||||||
set => RaiseAndSetIfChanged(ref _history, value);
|
set => RaiseAndSetIfChanged(ref _history, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProfileConfiguration? ProfileConfiguration => _profileConfiguration?.Value;
|
|
||||||
|
|
||||||
public bool IsSuspended
|
public bool IsSuspended
|
||||||
{
|
{
|
||||||
get => _isSuspended?.Value ?? false;
|
get => _isSuspended?.Value ?? false;
|
||||||
|
|||||||
@ -46,7 +46,7 @@
|
|||||||
</TreeView.Styles>
|
</TreeView.Styles>
|
||||||
<TreeView.DataTemplates>
|
<TreeView.DataTemplates>
|
||||||
<TreeDataTemplate DataType="{x:Type core:NodeData}">
|
<TreeDataTemplate DataType="{x:Type core:NodeData}">
|
||||||
<StackPanel Margin="-15 1 0 1">
|
<StackPanel Margin="-15 1 0 1" Background="Transparent" PointerReleased="InputElement_OnPointerReleased">
|
||||||
<TextBlock Classes="BodyStrongTextBlockStyle" Text="{Binding Name}"></TextBlock>
|
<TextBlock Classes="BodyStrongTextBlockStyle" Text="{Binding Name}"></TextBlock>
|
||||||
<TextBlock Foreground="{DynamicResource TextFillColorSecondary}" Text="{Binding Description}"></TextBlock>
|
<TextBlock Foreground="{DynamicResource TextFillColorSecondary}" Text="{Binding Description}"></TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.Mixins;
|
using Avalonia.Controls.Mixins;
|
||||||
using Avalonia.Controls.PanAndZoom;
|
using Avalonia.Controls.PanAndZoom;
|
||||||
|
using Avalonia.Input;
|
||||||
using Avalonia.LogicalTree;
|
using Avalonia.LogicalTree;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
@ -26,4 +29,13 @@ public class NodePickerView : ReactiveUserControl<NodePickerViewModel>
|
|||||||
{
|
{
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InputElement_OnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is not IDataContextProvider {DataContext: NodeData nodeData} || ViewModel == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ViewModel.CreateNode(nodeData);
|
||||||
|
ViewModel.IsVisible = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -21,7 +21,6 @@ public class NodePickerViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
private bool _isVisible;
|
private bool _isVisible;
|
||||||
private Point _position;
|
private Point _position;
|
||||||
private DateTime _closed;
|
|
||||||
private string? _searchText;
|
private string? _searchText;
|
||||||
private object? _selectedNode;
|
private object? _selectedNode;
|
||||||
private IPin? _targetPin;
|
private IPin? _targetPin;
|
||||||
@ -43,8 +42,7 @@ public class NodePickerViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
if (DateTime.Now - _closed > TimeSpan.FromSeconds(10))
|
SearchText = null;
|
||||||
SearchText = null;
|
|
||||||
TargetPin = null;
|
TargetPin = null;
|
||||||
|
|
||||||
nodeSourceList.Edit(list =>
|
nodeSourceList.Edit(list =>
|
||||||
@ -54,24 +52,8 @@ public class NodePickerViewModel : ActivatableViewModelBase
|
|||||||
});
|
});
|
||||||
|
|
||||||
IsVisible = true;
|
IsVisible = true;
|
||||||
|
Disposable.Create(() => IsVisible = false).DisposeWith(d);
|
||||||
Disposable.Create(() =>
|
|
||||||
{
|
|
||||||
_closed = DateTime.Now;
|
|
||||||
IsVisible = false;
|
|
||||||
}).DisposeWith(d);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.WhenAnyValue(vm => vm.SelectedNode)
|
|
||||||
.WhereNotNull()
|
|
||||||
.Where(o => o is NodeData)
|
|
||||||
.Throttle(TimeSpan.FromMilliseconds(200), RxApp.MainThreadScheduler)
|
|
||||||
.Subscribe(data =>
|
|
||||||
{
|
|
||||||
CreateNode((NodeData) data);
|
|
||||||
IsVisible = false;
|
|
||||||
SelectedNode = null;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlyObservableCollection<DynamicData.List.IGrouping<NodeData, string>> Categories { get; }
|
public ReadOnlyObservableCollection<DynamicData.List.IGrouping<NodeData, string>> Categories { get; }
|
||||||
|
|||||||
@ -10,5 +10,6 @@
|
|||||||
<dataModelPicker:DataModelPickerButton Classes="condensed"
|
<dataModelPicker:DataModelPickerButton Classes="condensed"
|
||||||
DataModelPath="{CompiledBinding DataModelPath}"
|
DataModelPath="{CompiledBinding DataModelPath}"
|
||||||
Modules="{CompiledBinding Modules}"
|
Modules="{CompiledBinding Modules}"
|
||||||
ShowDataModelValues="{CompiledBinding ShowDataModelValues.Value}" />
|
ShowDataModelValues="{CompiledBinding ShowDataModelValues.Value}"
|
||||||
|
ShowFullPath="{CompiledBinding ShowFullPaths.Value}"/>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -1,5 +1,4 @@
|
|||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Events;
|
|
||||||
using Artemis.VisualScripting.Nodes.Operators.Screens;
|
using Artemis.VisualScripting.Nodes.Operators.Screens;
|
||||||
|
|
||||||
namespace Artemis.VisualScripting.Nodes.Operators;
|
namespace Artemis.VisualScripting.Nodes.Operators;
|
||||||
@ -11,13 +10,6 @@ public class EnumEqualsNode : Node<int, EnumEqualsNodeCustomViewModel>
|
|||||||
{
|
{
|
||||||
InputPin = CreateInputPin<Enum>();
|
InputPin = CreateInputPin<Enum>();
|
||||||
OutputPin = CreateOutputPin<bool>();
|
OutputPin = CreateOutputPin<bool>();
|
||||||
|
|
||||||
InputPin.PinConnected += InputPinOnPinConnected;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InputPinOnPinConnected(object? sender, SingleValueEventArgs<IPin> e)
|
|
||||||
{
|
|
||||||
Storage = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputPin<Enum> InputPin { get; }
|
public InputPin<Enum> InputPin { get; }
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user