1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-12 21:38:38 +00:00

Nodes - Added hotkey toggle and hotkey enable/disable nodes

This commit is contained in:
Robert 2023-01-31 00:01:05 +01:00
parent bef3a84e28
commit 704bdce68b
12 changed files with 387 additions and 3 deletions

View File

@ -16,7 +16,10 @@ public class Hotkey : CorePropertyChanged, IStorageModel
Entity = new ProfileConfigurationHotkeyEntity();
}
internal Hotkey(ProfileConfigurationHotkeyEntity entity)
/// <summary>
/// Creates a new instance of <see cref="Hotkey" /> based on the provided entity
/// </summary>
public Hotkey(ProfileConfigurationHotkeyEntity entity)
{
Entity = entity;
Load();
@ -32,7 +35,10 @@ public class Hotkey : CorePropertyChanged, IStorageModel
/// </summary>
public KeyboardModifierKey? Modifiers { get; set; }
internal ProfileConfigurationHotkeyEntity Entity { get; }
/// <summary>
/// Gets the entity used to store this hotkey
/// </summary>
public ProfileConfigurationHotkeyEntity Entity { get; }
/// <summary>
/// Determines whether the provided <see cref="ArtemisKeyboardKeyEventArgs" /> match the hotkey

View File

@ -8,6 +8,7 @@ using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using FluentAvalonia.Core;
using Humanizer;
using Material.Icons;
@ -47,7 +48,8 @@ public class HotkeyBox : UserControl
Hotkey.Key = (KeyboardKey?) e.Key;
Hotkey.Modifiers = (KeyboardModifierKey?) e.KeyModifiers;
UpdateDisplayTextBox();
HotkeyChanged?.Invoke(this, EventArgs.Empty);
e.Handled = true;
}
@ -134,4 +136,13 @@ public class HotkeyBox : UserControl
}
#endregion
#region Events
/// <summary>
/// Occurs when the hotkey changes.
/// </summary>
public event TypedEventHandler<HotkeyBox, EventArgs>? HotkeyChanged;
#endregion
}

View File

@ -39,6 +39,9 @@
<dataModelPicker:DataModelPickerButton></dataModelPicker:DataModelPickerButton>
<dataModelPicker:DataModelPickerButton Classes="condensed"></dataModelPicker:DataModelPickerButton>
<controls1:HotkeyBox></controls1:HotkeyBox>
<controls1:HotkeyBox Classes="condensed"></controls1:HotkeyBox>
</StackPanel>
</Border>
</Design.PreviewWith>
@ -110,4 +113,10 @@
<Setter Property="MinHeight" Value="24" />
</Style>
<Style Selector="controls1|HotkeyBox.condensed > TextBox#DisplayTextBox">
<Setter Property="Padding" Value="6 0" />
<Setter Property="FontSize" Value="13" />
<Setter Property="MinHeight" Value="24" />
</Style>
</Styles>

View File

@ -0,0 +1,74 @@
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.VisualScripting.Nodes.Input.Screens;
namespace Artemis.VisualScripting.Nodes.Input;
[Node("Hotkey enable/disable", "Outputs a boolean value enabled and disabled by a set of hotkeys", "Input", OutputType = typeof(bool))]
public class HotkeyEnableDisableNode : Node<HotkeyEnableDisableNodeEntity, HotkeyEnableDisableNodeCustomViewModel>, IDisposable
{
private readonly IInputService _inputService;
private Hotkey? _disableHotkey;
private Hotkey? _enableHotkey;
private bool _value;
private bool _retrievedInitialValue;
public HotkeyEnableDisableNode(IInputService inputService)
{
_inputService = inputService;
_inputService.KeyboardKeyUp += InputServiceOnKeyboardKeyUp;
InitialValue = CreateInputPin<bool>();
Output = CreateOutputPin<bool>();
StorageModified += OnStorageModified;
}
public InputPin<bool> InitialValue { get; }
public OutputPin<bool> Output { get; }
public override void Initialize(INodeScript script)
{
LoadHotkeys();
}
public override void Evaluate()
{
if (!_retrievedInitialValue)
{
_value = InitialValue.Value;
_retrievedInitialValue = true;
}
Output.Value = _value;
}
private void OnStorageModified(object? sender, EventArgs e)
{
LoadHotkeys();
}
private void LoadHotkeys()
{
if (Storage == null)
return;
_enableHotkey = Storage.EnableHotkey != null ? new Hotkey(Storage.EnableHotkey) : null;
_disableHotkey = Storage.DisableHotkey != null ? new Hotkey(Storage.DisableHotkey) : null;
}
private void InputServiceOnKeyboardKeyUp(object? sender, ArtemisKeyboardKeyEventArgs e)
{
if (Storage == null)
return;
if (_disableHotkey != null && _disableHotkey.MatchesEventArgs(e))
_value = false;
else if (_enableHotkey != null && _enableHotkey.MatchesEventArgs(e))
_value = true;
}
public void Dispose()
{
_inputService.KeyboardKeyUp -= InputServiceOnKeyboardKeyUp;
}
}

View File

@ -0,0 +1,18 @@
using Artemis.Core;
using Artemis.Storage.Entities.Profile;
namespace Artemis.VisualScripting.Nodes.Input;
public class HotkeyEnableDisableNodeEntity
{
public HotkeyEnableDisableNodeEntity(Hotkey? enableHotkey, Hotkey? disableHotkey)
{
enableHotkey?.Save();
EnableHotkey = enableHotkey?.Entity;
disableHotkey?.Save();
DisableHotkey = disableHotkey?.Entity;
}
public ProfileConfigurationHotkeyEntity? EnableHotkey { get; set; }
public ProfileConfigurationHotkeyEntity? DisableHotkey { get; set; }
}

View File

@ -0,0 +1,69 @@
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.VisualScripting.Nodes.Input.Screens;
namespace Artemis.VisualScripting.Nodes.Input;
[Node("Hotkey toggle", "Outputs a boolean value toggled by a hotkey", "Input", OutputType = typeof(bool))]
public class HotkeyToggleNode : Node<HotkeyEnableDisableNodeEntity, HotkeyToggleNodeCustomViewModel>, IDisposable
{
private readonly IInputService _inputService;
private Hotkey? _toggleHotkey;
private bool _value;
private bool _retrievedInitialValue;
public HotkeyToggleNode(IInputService inputService)
{
_inputService = inputService;
_inputService.KeyboardKeyUp += InputServiceOnKeyboardKeyUp;
InitialValue = CreateInputPin<bool>();
Output = CreateOutputPin<bool>();
StorageModified += OnStorageModified;
}
public InputPin<bool> InitialValue { get; }
public OutputPin<bool> Output { get; }
public override void Initialize(INodeScript script)
{
LoadHotkeys();
}
public override void Evaluate()
{
if (!_retrievedInitialValue)
{
_value = InitialValue.Value;
_retrievedInitialValue = true;
}
Output.Value = _value;
}
private void OnStorageModified(object? sender, EventArgs e)
{
LoadHotkeys();
}
private void LoadHotkeys()
{
if (Storage == null)
return;
_toggleHotkey = Storage.EnableHotkey != null ? new Hotkey(Storage.EnableHotkey) : null;
}
private void InputServiceOnKeyboardKeyUp(object? sender, ArtemisKeyboardKeyEventArgs e)
{
if (Storage == null)
return;
if (_toggleHotkey != null && _toggleHotkey.MatchesEventArgs(e))
_value = !_value;
}
public void Dispose()
{
_inputService.KeyboardKeyUp -= InputServiceOnKeyboardKeyUp;
}
}

View File

@ -0,0 +1,16 @@
<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:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
xmlns:screens="clr-namespace:Artemis.VisualScripting.Nodes.Input.Screens"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.VisualScripting.Nodes.Input.Screens.HotkeyEnableDisableNodeCustomView"
x:DataType="screens:HotkeyEnableDisableNodeCustomViewModel">
<StackPanel>
<TextBlock FontSize="13" Margin="0 -2 0 5">Enable</TextBlock>
<shared:HotkeyBox Classes="condensed" Hotkey="{CompiledBinding EnableHotkey}" HotkeyChanged="HotkeyBox_OnHotkeyChanged" MinWidth="75" />
<TextBlock FontSize="13" Margin="0 5">Disable</TextBlock>
<shared:HotkeyBox Classes="condensed" Hotkey="{CompiledBinding DisableHotkey}" HotkeyChanged="HotkeyBox_OnHotkeyChanged" MinWidth="75" />
</StackPanel>
</UserControl>

View File

@ -0,0 +1,25 @@
using Artemis.UI.Shared;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.VisualScripting.Nodes.Input.Screens;
public partial class HotkeyEnableDisableNodeCustomView : ReactiveUserControl<HotkeyEnableDisableNodeCustomViewModel>
{
public HotkeyEnableDisableNodeCustomView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
private void HotkeyBox_OnHotkeyChanged(HotkeyBox sender, EventArgs args)
{
ViewModel?.Save();
}
}

View File

@ -0,0 +1,65 @@
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;
namespace Artemis.VisualScripting.Nodes.Input.Screens;
public class HotkeyEnableDisableNodeCustomViewModel : CustomNodeViewModel
{
private readonly HotkeyEnableDisableNode _enableDisableNode;
private readonly INodeEditorService _nodeEditorService;
private Hotkey? _enableHotkey;
private Hotkey? _disableHotkey;
private bool _updating;
/// <inheritdoc />
public HotkeyEnableDisableNodeCustomViewModel(HotkeyEnableDisableNode enableDisableNode, INodeScript script, INodeEditorService nodeEditorService) : base(enableDisableNode, script)
{
_enableDisableNode = enableDisableNode;
_nodeEditorService = nodeEditorService;
this.WhenActivated(d =>
{
Observable.FromEventPattern(x => _enableDisableNode.StorageModified += x, x => _enableDisableNode.StorageModified -= x).Subscribe(_ => Update()).DisposeWith(d);
Update();
});
}
private void Update()
{
_updating = true;
EnableHotkey = _enableDisableNode.Storage?.EnableHotkey != null ? new Hotkey(_enableDisableNode.Storage.EnableHotkey) : null;
DisableHotkey = _enableDisableNode.Storage?.DisableHotkey != null ? new Hotkey(_enableDisableNode.Storage.DisableHotkey) : null;
_updating = false;
}
public Hotkey? EnableHotkey
{
get => _enableHotkey;
set => this.RaiseAndSetIfChanged(ref _enableHotkey, value);
}
public Hotkey? DisableHotkey
{
get => _disableHotkey;
set => this.RaiseAndSetIfChanged(ref _disableHotkey, value);
}
public void Save()
{
if (_updating)
return;
_nodeEditorService.ExecuteCommand(
Script,
new UpdateStorage<HotkeyEnableDisableNodeEntity>(_enableDisableNode, new HotkeyEnableDisableNodeEntity(EnableHotkey, DisableHotkey), "hotkey")
);
}
}

View File

@ -0,0 +1,11 @@
<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:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
xmlns:screens="clr-namespace:Artemis.VisualScripting.Nodes.Input.Screens"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.VisualScripting.Nodes.Input.Screens.HotkeyToggleNodeCustomView"
x:DataType="screens:HotkeyToggleNodeCustomViewModel">
<shared:HotkeyBox Classes="condensed" Hotkey="{CompiledBinding ToggleHotkey}" HotkeyChanged="HotkeyBox_OnHotkeyChanged" MinWidth="75" />
</UserControl>

View File

@ -0,0 +1,25 @@
using Artemis.UI.Shared;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.VisualScripting.Nodes.Input.Screens;
public partial class HotkeyToggleNodeCustomView : ReactiveUserControl<HotkeyToggleNodeCustomViewModel>
{
public HotkeyToggleNodeCustomView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
private void HotkeyBox_OnHotkeyChanged(HotkeyBox sender, EventArgs args)
{
ViewModel?.Save();
}
}

View File

@ -0,0 +1,55 @@
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;
namespace Artemis.VisualScripting.Nodes.Input.Screens;
public class HotkeyToggleNodeCustomViewModel : CustomNodeViewModel
{
private readonly HotkeyToggleNode _toggleNode;
private readonly INodeEditorService _nodeEditorService;
private Hotkey? _toggleHotkey;
private bool _updating;
/// <inheritdoc />
public HotkeyToggleNodeCustomViewModel(HotkeyToggleNode toggleNode, INodeScript script, INodeEditorService nodeEditorService) : base(toggleNode, script)
{
_toggleNode = toggleNode;
_nodeEditorService = nodeEditorService;
this.WhenActivated(d =>
{
Observable.FromEventPattern(x => _toggleNode.StorageModified += x, x => _toggleNode.StorageModified -= x).Subscribe(_ => Update()).DisposeWith(d);
Update();
});
}
private void Update()
{
_updating = true;
ToggleHotkey = _toggleNode.Storage?.EnableHotkey != null ? new Hotkey(_toggleNode.Storage.EnableHotkey) : null;
_updating = false;
}
public Hotkey? ToggleHotkey
{
get => _toggleHotkey;
set => this.RaiseAndSetIfChanged(ref _toggleHotkey, value);
}
public void Save()
{
if (_updating)
return;
_nodeEditorService.ExecuteCommand(
Script,
new UpdateStorage<HotkeyEnableDisableNodeEntity>(_toggleNode, new HotkeyEnableDisableNodeEntity(ToggleHotkey, null), "hotkey")
);
}
}