diff --git a/src/Artemis.Core/Models/Profile/Conditions/EventCondition.cs b/src/Artemis.Core/Models/Profile/Conditions/EventCondition.cs index 6c8fd2c9a..d467ba655 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/EventCondition.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/EventCondition.cs @@ -13,7 +13,7 @@ public class EventCondition : CorePropertyChanged, INodeScriptCondition { private readonly string _displayName; private readonly EventConditionEntity _entity; - private readonly EventDefaultNode _eventNode; + private EventDefaultNode _eventNode; private DataModelPath? _eventPath; private DateTime _lastProcessedTrigger; private EventOverlapMode _overlapMode; @@ -199,6 +199,7 @@ public class EventCondition : CorePropertyChanged, INodeScriptCondition Script = _entity.Script != null ? new NodeScript($"Activate {_displayName}", $"Whether or not the event should activate the {_displayName}", _entity.Script, ProfileElement.Profile) : new NodeScript($"Activate {_displayName}", $"Whether or not the event should activate the {_displayName}", ProfileElement.Profile); + UpdateEventNode(); } /// @@ -219,8 +220,15 @@ public class EventCondition : CorePropertyChanged, INodeScriptCondition public void LoadNodeScript() { 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(); Script.LoadConnections(); + } #endregion @@ -253,13 +261,13 @@ public enum EventOverlapMode /// Restart, - /// - /// Ignore subsequent event fires until the timeline finishes - /// - Ignore, - /// /// Play another copy of the timeline on top of the current run /// - Copy + Copy, + + /// + /// Ignore subsequent event fires until the timeline finishes + /// + Ignore } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs index 3afb7b74f..769816e4e 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -72,6 +72,30 @@ namespace Artemis.Core Initialize(); } + /// + /// Creates a new instance of the class by copying the provided . + /// + /// The layer to copy + /// The parent of the layer + public Layer(Layer source, ProfileElement parent) : base(parent, parent.Profile) + { + LayerEntity = CoreJson.DeserializeObject(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(); + Leds = new ReadOnlyCollection(_leds); + + Adapter = new LayerAdapter(this); + Load(); + Initialize(); + } + /// /// A collection of all the LEDs this layer is assigned to. /// @@ -349,7 +373,7 @@ namespace Artemis.Core if (ShouldBeEnabled) Enable(); - else if (Timeline.IsFinished) + else if (Timeline.IsFinished && !Children.Any()) Disable(); if (Timeline.Delta == TimeSpan.Zero) @@ -365,15 +389,16 @@ namespace Artemis.Core // Remove children that finished their timeline and update the rest for (int index = 0; index < Children.Count; index++) { - ProfileElement profileElement = Children[index]; - if (((Layer) profileElement).Timeline.IsFinished) + Layer child = (Layer) Children[index]; + if (!child.Timeline.IsFinished) { - RemoveChild(profileElement); - profileElement.Dispose(); - index--; + child.Update(deltaTime); + continue; } - else - profileElement.Update(deltaTime); + + RemoveChild(child); + child.Dispose(); + index--; } } @@ -383,6 +408,12 @@ namespace Artemis.Core if (Disposed) throw new ObjectDisposedException("Layer"); + RenderSelf(canvas, basePosition); + RenderChildren(canvas, basePosition); + } + + private void RenderSelf(SKCanvas canvas, SKPointI basePosition) + { // Ensure the layer is ready if (!Enabled || Path == null || LayerShape?.Path == null || !General.PropertiesInitialized || !Transform.PropertiesInitialized || !Leds.Any()) return; @@ -454,6 +485,13 @@ namespace Artemis.Core 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); + } + /// public override void Enable() { @@ -523,11 +561,11 @@ namespace Artemis.Core /// public void CreateCopyAsChild() { - throw new NotImplementedException(); - - // Create a copy of the layer and it's properties - - // Add to children + Layer copy = new(this, this); + copy.AddLeds(Leds); + copy.Enable(); + copy.Timeline.JumpToStart(); + AddChild(copy); } internal void CalculateRenderProperties() diff --git a/src/Artemis.Core/Stores/NodeTypeStore.cs b/src/Artemis.Core/Stores/NodeTypeStore.cs index aee2896e3..70caca7b1 100644 --- a/src/Artemis.Core/Stores/NodeTypeStore.cs +++ b/src/Artemis.Core/Stores/NodeTypeStore.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Artemis.Storage.Entities.Profile.Nodes; using SkiaSharp; 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) { - return Registrations.FirstOrDefault(r => r.Plugin.Guid == pluginGuid && r.NodeData.Type.Name == type); + return Registrations.FirstOrDefault(r => r.MatchesEntity(entity)); } } diff --git a/src/Artemis.Core/Stores/Registrations/NodeTypeRegistration.cs b/src/Artemis.Core/Stores/Registrations/NodeTypeRegistration.cs index 799bee80e..02bdaa396 100644 --- a/src/Artemis.Core/Stores/Registrations/NodeTypeRegistration.cs +++ b/src/Artemis.Core/Stores/Registrations/NodeTypeRegistration.cs @@ -1,4 +1,5 @@ using System; +using Artemis.Storage.Entities.Profile.Nodes; using SkiaSharp; namespace Artemis.Core @@ -37,6 +38,16 @@ namespace Artemis.Core if (IsInStore) NodeTypeStore.Remove(this); } + + /// + /// Determines whether the provided entity matches this node type registration. + /// + /// The entity to check. + /// if the entity matches this registration; otherwise . + public bool MatchesEntity(NodeEntity entity) + { + return Plugin.Guid == entity.PluginId && NodeData.Type.Name == entity.Type; + } } /// diff --git a/src/Artemis.Core/VisualScripting/Interfaces/INode.cs b/src/Artemis.Core/VisualScripting/Interfaces/INode.cs index 56bd18103..50e83a7a1 100644 --- a/src/Artemis.Core/VisualScripting/Interfaces/INode.cs +++ b/src/Artemis.Core/VisualScripting/Interfaces/INode.cs @@ -9,6 +9,11 @@ namespace Artemis.Core /// public interface INode : INotifyPropertyChanged { + /// + /// Gets or sets the ID of the node. + /// + Guid Id { get; set; } + /// /// Gets the name of the node /// diff --git a/src/Artemis.Core/VisualScripting/Interfaces/INodeScript.cs b/src/Artemis.Core/VisualScripting/Interfaces/INodeScript.cs index 4a0720f86..01e1a37ec 100644 --- a/src/Artemis.Core/VisualScripting/Interfaces/INodeScript.cs +++ b/src/Artemis.Core/VisualScripting/Interfaces/INodeScript.cs @@ -59,6 +59,9 @@ namespace Artemis.Core /// /// Removes a node from the script + /// + /// Note: If the node is you must dispose it yourself, unless you plan to reuse the node. + /// /// /// The node to remove void RemoveNode(INode node); diff --git a/src/Artemis.Core/VisualScripting/Internal/DefaultNode.cs b/src/Artemis.Core/VisualScripting/Internal/DefaultNode.cs new file mode 100644 index 000000000..135c5901a --- /dev/null +++ b/src/Artemis.Core/VisualScripting/Internal/DefaultNode.cs @@ -0,0 +1,36 @@ +using System; + +namespace Artemis.Core.Internal +{ + /// + /// Represents a kind of node that cannot be deleted inside a . + /// + public interface IDefaultNode : INode + { + } + + /// + /// Represents a kind of node that cannot be deleted inside a . + /// + public abstract class DefaultNode : Node, IDefaultNode + { + #region Properties & Fields + + /// + public override bool IsDefaultNode => true; + + #endregion + + #region Constructors + + /// + protected DefaultNode(Guid id, string name, string description = "") : base(name, description) + { + Id = id; + Name = name; + Description = description; + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Artemis.Core/VisualScripting/Internal/EventDefaultNode.cs b/src/Artemis.Core/VisualScripting/Internal/EventDefaultNode.cs index ef7f2ffb9..4e35b99e6 100644 --- a/src/Artemis.Core/VisualScripting/Internal/EventDefaultNode.cs +++ b/src/Artemis.Core/VisualScripting/Internal/EventDefaultNode.cs @@ -7,19 +7,18 @@ using Humanizer; 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 _propertyPins; private readonly List _pinBucket = new(); 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(); } - public override bool IsDefaultNode => true; - public void CreatePins(IDataModelEvent? dataModelEvent) { if (_dataModelEvent == dataModelEvent) @@ -33,9 +32,12 @@ namespace Artemis.Core.Internal if (dataModelEvent == null) 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)))) + { _propertyPins.Add(propertyInfo, CreateOrAddOutputPin(propertyInfo.PropertyType, propertyInfo.Name.Humanize())); + } } public override void Evaluate() diff --git a/src/Artemis.Core/VisualScripting/Internal/ExitNode.cs b/src/Artemis.Core/VisualScripting/Internal/ExitNode.cs index 978aa3f76..bdc3f7ab0 100644 --- a/src/Artemis.Core/VisualScripting/Internal/ExitNode.cs +++ b/src/Artemis.Core/VisualScripting/Internal/ExitNode.cs @@ -1,12 +1,16 @@ -namespace Artemis.Core.Internal +using System; + +namespace Artemis.Core.Internal { internal interface IExitNode : INode - { } + { + protected static readonly Guid NodeId = new("410C824D-C5E3-4E3A-8080-D50F6C8B83B8"); + } internal class ExitNode : Node, IExitNode { #region Properties & Fields - + public InputPin Input { get; } public T? Value { get; private set; } @@ -19,6 +23,7 @@ public ExitNode(string name, string description = "") { + Id = IExitNode.NodeId; Name = name; Description = description; diff --git a/src/Artemis.Core/VisualScripting/Node.cs b/src/Artemis.Core/VisualScripting/Node.cs index 4622a1441..70804e43e 100644 --- a/src/Artemis.Core/VisualScripting/Node.cs +++ b/src/Artemis.Core/VisualScripting/Node.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using Artemis.Core.Properties; using Ninject; using Ninject.Parameters; @@ -16,6 +15,15 @@ public abstract class Node : CorePropertyChanged, INode public event EventHandler? Resetting; #region Properties & Fields + + private Guid _id; + + /// + public Guid Id + { + get => _id; + set => SetAndNotify(ref _id , value); + } private string _name; @@ -65,7 +73,7 @@ public abstract class Node : CorePropertyChanged, INode public IReadOnlyCollection Pins => new ReadOnlyCollection(_pins); private readonly List _pinCollections = new(); - + /// public IReadOnlyCollection PinCollections => new ReadOnlyCollection(_pinCollections); diff --git a/src/Artemis.Core/VisualScripting/NodeScript.cs b/src/Artemis.Core/VisualScripting/NodeScript.cs index f67476ceb..22909973f 100644 --- a/src/Artemis.Core/VisualScripting/NodeScript.cs +++ b/src/Artemis.Core/VisualScripting/NodeScript.cs @@ -16,7 +16,9 @@ namespace Artemis.Core { 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(); } /// @@ -153,41 +155,38 @@ namespace Artemis.Core { lock (_nodes) { - List removeNodes = _nodes.Where(n => !n.IsExitNode).ToList(); + // Remove nodes no longer on the entity + List removeNodes = _nodes.Where(n => Entity.Nodes.All(e => e.Id != n.Id)).ToList(); foreach (INode removeNode in removeNodes) + { RemoveNode(removeNode); + if (removeNode is IDisposable disposable) + disposable.Dispose(); + } } - // Create nodes - foreach (NodeEntity entityNode in Entity.Nodes) + // Create missing nodes nodes + foreach (NodeEntity nodeEntity in Entity.Nodes) { - INode? node = LoadNode(entityNode, entityNode.IsExitNode ? ExitNode : null); - if (node == null) - continue; - - if (!entityNode.IsExitNode) - AddNode(node); + INode? node = Nodes.FirstOrDefault(n => n.Id == nodeEntity.Id); + // If the node already exists, apply the entity to it + if (node != null) + LoadExistingNode(node, nodeEntity); + else + { + INode? loaded = LoadNode(nodeEntity); + if (loaded != null) + AddNode(loaded); + } } LoadConnections(); } - private INode? LoadNode(NodeEntity nodeEntity, INode? node) + private void LoadExistingNode(INode node, NodeEntity nodeEntity) { - if (node == null) - { - 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; - } + node.X = nodeEntity.X; + node.Y = nodeEntity.Y; // Restore pin collections foreach (NodePinCollectionEntity entityNodePinCollection in nodeEntity.PinCollections) @@ -201,7 +200,17 @@ namespace Artemis.Core while (collection.Count() < entityNodePinCollection.Amount) 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; } @@ -213,10 +222,10 @@ namespace Artemis.Core List nodes = Nodes.ToList(); 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) continue; - INode? target = nodes.ElementAtOrDefault(nodeConnectionEntity.TargetNode); + INode? target = nodes.FirstOrDefault(n => n.Id == nodeConnectionEntity.TargetNode); if (target == null) continue; @@ -263,12 +272,11 @@ namespace Artemis.Core if (Nodes.Count() == 1) return; - int id = 0; foreach (INode node in Nodes) { NodeEntity nodeEntity = new() { - Id = id, + Id = node.Id, PluginId = NodeTypeStore.GetPlugin(node)?.Guid ?? Constants.CorePlugin.Guid, Type = node.GetType().Name, X = node.X, @@ -294,7 +302,6 @@ namespace Artemis.Core } Entity.Nodes.Add(nodeEntity); - id++; } // Store connections @@ -315,7 +322,6 @@ namespace Artemis.Core private void SavePins(INode node, int collectionId, IEnumerable pins) { int sourcePinId = 0; - List nodes = Nodes.ToList(); foreach (IPin sourcePin in pins.Where(p => p.Direction == PinDirection.Input)) { foreach (IPin targetPin in sourcePin.ConnectedTo) @@ -337,11 +343,11 @@ namespace Artemis.Core Entity.Connections.Add(new NodeConnectionEntity { SourceType = sourcePin.Type.Name, - SourceNode = nodes.IndexOf(node), + SourceNode = node.Id, SourcePinCollectionId = collectionId, SourcePinId = sourcePinId, TargetType = targetPin.Type.Name, - TargetNode = nodes.IndexOf(targetPin.Node), + TargetNode = targetPin.Node.Id, TargetPinCollectionId = targetPinCollectionId, TargetPinId = targetPinId }); diff --git a/src/Artemis.Storage/Entities/Profile/Nodes/NodeConnectionEntity.cs b/src/Artemis.Storage/Entities/Profile/Nodes/NodeConnectionEntity.cs index 1536f31ab..d3946f77d 100644 --- a/src/Artemis.Storage/Entities/Profile/Nodes/NodeConnectionEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/Nodes/NodeConnectionEntity.cs @@ -1,10 +1,12 @@ -namespace Artemis.Storage.Entities.Profile.Nodes +using System; + +namespace Artemis.Storage.Entities.Profile.Nodes { public class NodeConnectionEntity { public string SourceType { get; set; } - public int SourceNode { get; set; } - public int TargetNode { get; set; } + public Guid SourceNode { get; set; } + public Guid TargetNode { get; set; } public int SourcePinCollectionId { get; set; } public int SourcePinId { get; set; } public string TargetType { get; set; } diff --git a/src/Artemis.Storage/Entities/Profile/Nodes/NodeEntity.cs b/src/Artemis.Storage/Entities/Profile/Nodes/NodeEntity.cs index 8a99bb8f0..dc858ba91 100644 --- a/src/Artemis.Storage/Entities/Profile/Nodes/NodeEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/Nodes/NodeEntity.cs @@ -10,7 +10,7 @@ namespace Artemis.Storage.Entities.Profile.Nodes PinCollections = new List(); } - public int Id { get; set; } + public Guid Id { get; set; } public string Type { get; set; } public Guid PluginId { get; set; } diff --git a/src/Artemis.UI.Shared/Styles/Controls/DataModelPickerButton.axaml b/src/Artemis.UI.Shared/Styles/Controls/DataModelPickerButton.axaml index 23e117502..b573b409b 100644 --- a/src/Artemis.UI.Shared/Styles/Controls/DataModelPickerButton.axaml +++ b/src/Artemis.UI.Shared/Styles/Controls/DataModelPickerButton.axaml @@ -39,7 +39,8 @@ + TextAlignment="Left" + TextTrimming="CharacterEllipsis"/> + DataModelPath="{CompiledBinding EventPath}" + ShowFullPath="{CompiledBinding ShowFullPaths.Value}"/> When the event fires.. diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/EventConditionViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/EventConditionViewModel.cs index 144f5ae33..4ed70bae5 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/EventConditionViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/EventConditionViewModel.cs @@ -4,6 +4,7 @@ using System.Reactive; using System.Reactive.Linq; using System.Threading.Tasks; using Artemis.Core; +using Artemis.Core.Services; using Artemis.UI.Screens.VisualScripting; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; @@ -20,15 +21,17 @@ public class EventConditionViewModel : ActivatableViewModelBase private readonly IProfileEditorService _profileEditorService; private readonly ObservableAsPropertyHelper _showOverlapOptions; private readonly IWindowService _windowService; + private readonly ISettingsService _settingsService; private ObservableAsPropertyHelper? _eventPath; private ObservableAsPropertyHelper? _selectedOverlapMode; private ObservableAsPropertyHelper? _selectedTriggerMode; - public EventConditionViewModel(EventCondition eventCondition, IProfileEditorService profileEditorService, IWindowService windowService) + public EventConditionViewModel(EventCondition eventCondition, IProfileEditorService profileEditorService, IWindowService windowService, ISettingsService settingsService) { _eventCondition = eventCondition; _profileEditorService = profileEditorService; _windowService = windowService; + _settingsService = settingsService; _showOverlapOptions = this.WhenAnyValue(vm => vm.SelectedTriggerMode) .Select(m => m == 0) .ToProperty(this, vm => vm.ShowOverlapOptions); @@ -47,6 +50,7 @@ public class EventConditionViewModel : ActivatableViewModelBase public ReactiveCommand OpenEditor { get; } public bool ShowOverlapOptions => _showOverlapOptions.Value; public bool IsConditionForLayer => _eventCondition.ProfileElement is Layer; + public PluginSetting ShowFullPaths => _settingsService.GetSetting("ProfileEditor.ShowFullPaths", false); public DataModelPath? EventPath { diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarView.axaml index f1ef33ff0..e3a38b5e6 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarView.axaml @@ -128,40 +128,41 @@ + Command="{CompiledBinding ToggleBooleanSetting}" + CommandParameter="{CompiledBinding FocusSelectedLayer}"> - - + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarViewModel.cs index 3a04235e4..9f5e7369f 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarViewModel.cs @@ -1,4 +1,5 @@ using System; +using System.Reactive; using System.Reactive.Disposables; using System.Reactive.Linq; using Artemis.Core; @@ -12,13 +13,15 @@ namespace Artemis.UI.Screens.ProfileEditor.MenuBar; public class MenuBarViewModel : ActivatableViewModelBase { private readonly IProfileService _profileService; + private readonly ISettingsService _settingsService; private ProfileEditorHistory? _history; private ObservableAsPropertyHelper? _profileConfiguration; private ObservableAsPropertyHelper? _isSuspended; - public MenuBarViewModel(IProfileEditorService profileEditorService, IProfileService profileService) + public MenuBarViewModel(IProfileEditorService profileEditorService, IProfileService profileService, ISettingsService settingsService) { _profileService = profileService; + _settingsService = settingsService; this.WhenActivated(d => { profileEditorService.History.Subscribe(history => History = history).DisposeWith(d); @@ -29,16 +32,30 @@ public class MenuBarViewModel : ActivatableViewModelBase .ToProperty(this, vm => vm.IsSuspended) .DisposeWith(d); }); + + ToggleBooleanSetting = ReactiveCommand.Create>(ExecuteToggleBooleanSetting); } + private void ExecuteToggleBooleanSetting(PluginSetting setting) + { + setting.Value = !setting.Value; + setting.Save(); + } + + public ReactiveCommand, Unit> ToggleBooleanSetting { get; } + public ProfileConfiguration? ProfileConfiguration => _profileConfiguration?.Value; + public PluginSetting FocusSelectedLayer => _settingsService.GetSetting("ProfileEditor.FocusSelectedLayer", false); + public PluginSetting ShowDataModelValues => _settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false); + public PluginSetting ShowFullPaths => _settingsService.GetSetting("ProfileEditor.ShowFullPaths", false); + public PluginSetting AlwaysShowValues => _settingsService.GetSetting("ProfileEditor.AlwaysShowValues", false); + public PluginSetting AlwaysApplyDataBindings => _settingsService.GetSetting("ProfileEditor.AlwaysApplyDataBindings", false); + public ProfileEditorHistory? History { get => _history; set => RaiseAndSetIfChanged(ref _history, value); } - public ProfileConfiguration? ProfileConfiguration => _profileConfiguration?.Value; - public bool IsSuspended { get => _isSuspended?.Value ?? false; diff --git a/src/Artemis.UI/Screens/VisualScripting/NodePickerView.axaml b/src/Artemis.UI/Screens/VisualScripting/NodePickerView.axaml index db9c8adae..2b0f71345 100644 --- a/src/Artemis.UI/Screens/VisualScripting/NodePickerView.axaml +++ b/src/Artemis.UI/Screens/VisualScripting/NodePickerView.axaml @@ -46,7 +46,7 @@ - + diff --git a/src/Artemis.UI/Screens/VisualScripting/NodePickerView.axaml.cs b/src/Artemis.UI/Screens/VisualScripting/NodePickerView.axaml.cs index 9ff6e7551..82dd2cbb4 100644 --- a/src/Artemis.UI/Screens/VisualScripting/NodePickerView.axaml.cs +++ b/src/Artemis.UI/Screens/VisualScripting/NodePickerView.axaml.cs @@ -1,8 +1,11 @@ using System; using System.Reactive.Linq; +using Artemis.Core; +using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Mixins; using Avalonia.Controls.PanAndZoom; +using Avalonia.Input; using Avalonia.LogicalTree; using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; @@ -26,4 +29,13 @@ public class NodePickerView : ReactiveUserControl { 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; + } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/VisualScripting/NodePickerViewModel.cs b/src/Artemis.UI/Screens/VisualScripting/NodePickerViewModel.cs index b19f4e559..ae81eebab 100644 --- a/src/Artemis.UI/Screens/VisualScripting/NodePickerViewModel.cs +++ b/src/Artemis.UI/Screens/VisualScripting/NodePickerViewModel.cs @@ -21,7 +21,6 @@ public class NodePickerViewModel : ActivatableViewModelBase private bool _isVisible; private Point _position; - private DateTime _closed; private string? _searchText; private object? _selectedNode; private IPin? _targetPin; @@ -43,8 +42,7 @@ public class NodePickerViewModel : ActivatableViewModelBase this.WhenActivated(d => { - if (DateTime.Now - _closed > TimeSpan.FromSeconds(10)) - SearchText = null; + SearchText = null; TargetPin = null; nodeSourceList.Edit(list => @@ -54,24 +52,8 @@ public class NodePickerViewModel : ActivatableViewModelBase }); IsVisible = true; - - Disposable.Create(() => - { - _closed = DateTime.Now; - IsVisible = false; - }).DisposeWith(d); + Disposable.Create(() => 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> Categories { get; } diff --git a/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelNodeCustomView.axaml b/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelNodeCustomView.axaml index 41f87c694..1d7ae7c0d 100644 --- a/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelNodeCustomView.axaml +++ b/src/Artemis.VisualScripting/Nodes/DataModel/Screens/DataModelNodeCustomView.axaml @@ -10,5 +10,6 @@ + ShowDataModelValues="{CompiledBinding ShowDataModelValues.Value}" + ShowFullPath="{CompiledBinding ShowFullPaths.Value}"/> \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/Operators/EnumEqualsNode.cs b/src/Artemis.VisualScripting/Nodes/Operators/EnumEqualsNode.cs index 7a9363d68..798ae1a47 100644 --- a/src/Artemis.VisualScripting/Nodes/Operators/EnumEqualsNode.cs +++ b/src/Artemis.VisualScripting/Nodes/Operators/EnumEqualsNode.cs @@ -1,5 +1,4 @@ using Artemis.Core; -using Artemis.Core.Events; using Artemis.VisualScripting.Nodes.Operators.Screens; namespace Artemis.VisualScripting.Nodes.Operators; @@ -11,13 +10,6 @@ public class EnumEqualsNode : Node { InputPin = CreateInputPin(); OutputPin = CreateOutputPin(); - - InputPin.PinConnected += InputPinOnPinConnected; - } - - private void InputPinOnPinConnected(object? sender, SingleValueEventArgs e) - { - Storage = 0; } public InputPin InputPin { get; }