1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Nodes - Added Pressed Key Position node

This commit is contained in:
Robert 2022-10-21 10:37:02 +02:00
parent 02cd0dd54c
commit 147e050e69
5 changed files with 244 additions and 0 deletions

View File

@ -0,0 +1,73 @@
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.VisualScripting.Nodes.Input.Screens;
using SkiaSharp;
using static Artemis.VisualScripting.Nodes.Input.PressedKeyPositionNodeEntity;
namespace Artemis.VisualScripting.Nodes.Input;
[Node("Pressed Key Position", "Outputs the position of a pressed key relative to a layer", "Input", OutputType = typeof(Numeric))]
public class PressedKeyPositionNode : Node<PressedKeyPositionNodeEntity, PressedKeyPositionNodeCustomViewModel>, IDisposable
{
private readonly IInputService _inputService;
private Layer? _layer;
private SKPoint _ledPosition;
private Profile? _profile;
public PressedKeyPositionNode(IInputService inputService)
{
_inputService = inputService;
XPosition = CreateOutputPin<Numeric>("X");
YPosition = CreateOutputPin<Numeric>("Y");
StorageModified += OnStorageModified;
_inputService.KeyboardKeyDown += InputServiceOnKeyboardKeyDown;
_inputService.KeyboardKeyUp += InputServiceOnKeyboardKeyUp;
}
public OutputPin<Numeric> XPosition { get; }
public OutputPin<Numeric> YPosition { get; }
public override void Initialize(INodeScript script)
{
Storage ??= new PressedKeyPositionNodeEntity();
_profile = script.Context as Profile;
_layer = _profile?.GetAllLayers().FirstOrDefault(l => l.EntityId == Storage.LayerId);
}
public override void Evaluate()
{
XPosition.Value = _ledPosition.X;
YPosition.Value = _ledPosition.Y;
}
private void InputServiceOnKeyboardKeyDown(object? sender, ArtemisKeyboardKeyEventArgs e)
{
if (Storage?.RespondTo is KeyPressType.Down or KeyPressType.UpDown)
SetLedPosition(e.Led);
}
private void InputServiceOnKeyboardKeyUp(object? sender, ArtemisKeyboardKeyEventArgs e)
{
if (Storage?.RespondTo is KeyPressType.Up or KeyPressType.UpDown)
SetLedPosition(e.Led);
}
private void SetLedPosition(ArtemisLed? led)
{
if (_layer != null && led != null)
_ledPosition = new SKPoint((led.AbsoluteRectangle.MidX - _layer.Bounds.Left) / _layer.Bounds.Width, (led.AbsoluteRectangle.MidY - _layer.Bounds.Top) / _layer.Bounds.Height);
}
private void OnStorageModified(object? sender, EventArgs e)
{
_layer = _profile?.GetAllLayers().FirstOrDefault(l => l.EntityId == Storage?.LayerId);
}
public void Dispose()
{
_inputService.KeyboardKeyDown -= InputServiceOnKeyboardKeyDown;
_inputService.KeyboardKeyUp -= InputServiceOnKeyboardKeyUp;
}
}

View File

@ -0,0 +1,29 @@
using System.ComponentModel;
namespace Artemis.VisualScripting.Nodes.Input;
public class PressedKeyPositionNodeEntity
{
public PressedKeyPositionNodeEntity()
{
}
public PressedKeyPositionNodeEntity(Guid layerId, KeyPressType respondTo)
{
LayerId = layerId;
RespondTo = respondTo;
}
public Guid LayerId { get; set; }
public KeyPressType RespondTo { get; set; }
public enum KeyPressType
{
[Description("Up")]
Up,
[Description("Down")]
Down,
[Description("Up/down")]
UpDown
}
}

View File

@ -0,0 +1,29 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:screens="clr-namespace:Artemis.VisualScripting.Nodes.Input.Screens"
xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.VisualScripting.Nodes.Input.Screens.PressedKeyPositionNodeCustomView"
x:DataType="screens:PressedKeyPositionNodeCustomViewModel">
<StackPanel>
<TextBlock FontSize="13" Margin="0 -2 0 5">Layer</TextBlock>
<ComboBox Classes="condensed" Items="{CompiledBinding Layers}" SelectedItem="{CompiledBinding SelectedLayer}" PlaceholderText="Select a layer">
<ComboBox.ItemTemplate>
<DataTemplate DataType="core:Layer">
<StackPanel Spacing="5" Orientation="Horizontal">
<avalonia:MaterialIcon Kind="{CompiledBinding LayerBrush.Descriptor.Icon, FallbackValue=QuestionMark}" VerticalAlignment="Center" />
<TextBlock Text="{CompiledBinding Name}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock FontSize="13" Margin="0 5">Respond to</TextBlock>
<shared:EnumComboBox Classes="condensed" Value="{CompiledBinding RespondTo}"/>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,19 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.VisualScripting.Nodes.Input.Screens;
public partial class PressedKeyPositionNodeCustomView : ReactiveUserControl<PressedKeyPositionNodeCustomViewModel>
{
public PressedKeyPositionNodeCustomView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}

View File

@ -0,0 +1,94 @@
using System.Collections.ObjectModel;
using System.Reactive.Linq;
using Artemis.Core;
using Artemis.UI.Shared.Services.NodeEditor;
using Artemis.UI.Shared.Services.NodeEditor.Commands;
using Artemis.UI.Shared.VisualScripting;
using Avalonia.Controls.Mixins;
using ReactiveUI;
using static Artemis.VisualScripting.Nodes.Input.PressedKeyPositionNodeEntity;
namespace Artemis.VisualScripting.Nodes.Input.Screens;
public class PressedKeyPositionNodeCustomViewModel : CustomNodeViewModel
{
private readonly INodeEditorService _nodeEditorService;
private readonly Profile? _profile;
private readonly PressedKeyPositionNode _node;
private Layer? _selectedLayer;
private KeyPressType _respondTo;
public PressedKeyPositionNodeCustomViewModel(PressedKeyPositionNode node, INodeScript script, INodeEditorService nodeEditorService) : base(node, script)
{
_nodeEditorService = nodeEditorService;
_profile = script.Context as Profile;
_node = node;
Layers = new ObservableCollection<Layer>();
this.WhenActivated(d =>
{
if (_profile == null)
return;
Observable.FromEventPattern<ProfileElementEventArgs>(x => _profile.DescendentAdded += x, x => _profile.DescendentAdded -= x).Subscribe(_ => GetLayers()).DisposeWith(d);
Observable.FromEventPattern<ProfileElementEventArgs>(x => _profile.DescendentRemoved += x, x => _profile.DescendentRemoved -= x).Subscribe(_ => GetLayers()).DisposeWith(d);
Observable.FromEventPattern(x => _node.StorageModified += x, x => _node.StorageModified -= x).Subscribe(_ => Update()).DisposeWith(d);
GetLayers();
});
this.WhenAnyValue(vm => vm.SelectedLayer).Subscribe(UpdateSelectedLayer);
this.WhenAnyValue(vm => vm.RespondTo).Subscribe(UpdateSelectedRespondTo);
}
public ObservableCollection<Layer> Layers { get; }
public Layer? SelectedLayer
{
get => _selectedLayer;
set => this.RaiseAndSetIfChanged(ref _selectedLayer, value);
}
public KeyPressType RespondTo
{
get => _respondTo;
set => this.RaiseAndSetIfChanged(ref _respondTo, value);
}
private void GetLayers()
{
Layers.Clear();
if (_profile == null)
return;
foreach (Layer layer in _profile.GetAllLayers())
Layers.Add(layer);
Update();
}
private void Update()
{
SelectedLayer = Layers.FirstOrDefault(l => l.EntityId == _node.Storage?.LayerId);
RespondTo = _node.Storage?.RespondTo ?? KeyPressType.Up;
}
private void UpdateSelectedLayer(Layer? layer)
{
if (layer == null || _node.Storage?.LayerId == layer.EntityId)
return;
_nodeEditorService.ExecuteCommand(
Script,
new UpdateStorage<PressedKeyPositionNodeEntity>(_node, new PressedKeyPositionNodeEntity(layer.EntityId, _node.Storage?.RespondTo ?? KeyPressType.Up), "layer")
);
}
private void UpdateSelectedRespondTo(KeyPressType respondTo)
{
if (_node.Storage?.RespondTo == respondTo)
return;
_nodeEditorService.ExecuteCommand(Script, new UpdateStorage<PressedKeyPositionNodeEntity>(_node, new PressedKeyPositionNodeEntity(_node.Storage?.LayerId ?? Guid.Empty, respondTo), "layer"));
}
}