using System; using System.Linq; using Artemis.Core; using Artemis.Core.Services; using Avalonia; using Avalonia.Controls; using Avalonia.Data; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Markup.Xaml; using Avalonia.Threading; using DryIoc; using FluentAvalonia.Core; using Humanizer; using Material.Icons; namespace Artemis.UI.Shared; /// /// Represents a control that can be used to display or edit instances. /// public partial class HotkeyBox : UserControl { private readonly IInputService _inputService; /// /// Creates a new instance of the class /// public HotkeyBox() { _inputService = UI.Locator.Resolve(); InitializeComponent(); PropertyChanged += OnPropertyChanged; UpdateDisplayTextBox(); } /// protected override void OnGotFocus(GotFocusEventArgs e) { _inputService.KeyboardKeyDown += InputServiceOnKeyboardKeyDown; _inputService.KeyboardKeyUp += InputServiceOnKeyboardKeyUp; base.OnGotFocus(e); } /// protected override void OnLostFocus(RoutedEventArgs e) { _inputService.KeyboardKeyDown -= InputServiceOnKeyboardKeyDown; _inputService.KeyboardKeyUp -= InputServiceOnKeyboardKeyUp; base.OnLostFocus(e); } private void OnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) { if (e.Property == HotkeyProperty) UpdateDisplayTextBox(); } private void InputServiceOnKeyboardKeyDown(object? sender, ArtemisKeyboardKeyEventArgs e) { if (e.Key >= KeyboardKey.LeftShift && e.Key <= KeyboardKey.RightAlt) return; Hotkey ??= new Hotkey(); Hotkey.Key = e.Key; Hotkey.Modifiers = e.Modifiers; Dispatcher.UIThread.Post(() => { UpdateDisplayTextBox(); HotkeyChanged?.Invoke(this, EventArgs.Empty); }); } private void InputServiceOnKeyboardKeyUp(object? sender, ArtemisKeyboardKeyEventArgs e) { if (e.Modifiers == KeyboardModifierKey.None) Dispatcher.UIThread.Post(() => FocusManager.Instance?.Focus(null)); } private void UpdateDisplayTextBox() { string? display = null; if (Hotkey?.Modifiers != null) display = string.Join("+", Enum.GetValues().Skip(1).Where(m => Hotkey.Modifiers.Value.HasFlag(m)).Select(v => v.Humanize())); if (Hotkey?.Key != null) display = string.IsNullOrEmpty(display) ? Hotkey.Key.ToString() : $"{display}+{Hotkey.Key}"; DisplayTextBox.Text = display; DisplayTextBox.CaretIndex = DisplayTextBox.Text?.Length ?? 0; } private void Button_OnClick(object? sender, RoutedEventArgs e) { Hotkey = null; FocusManager.Instance?.Focus(null); UpdateDisplayTextBox(); } #region Properties /// /// Gets or sets the currently displayed icon as either a or an /// pointing to an SVG /// public static readonly StyledProperty HotkeyProperty = AvaloniaProperty.Register(nameof(Hotkey), defaultBindingMode: BindingMode.TwoWay); /// /// Gets or sets the watermark of the hotkey box when it is empty. /// public static readonly StyledProperty WatermarkProperty = AvaloniaProperty.Register(nameof(Watermark)); /// /// Gets or sets a boolean indicating whether the watermark should float above the hotkey box when it is not empty. /// public static readonly StyledProperty UseFloatingWatermarkProperty = AvaloniaProperty.Register(nameof(UseFloatingWatermark)); /// /// Gets or sets the currently displayed icon as either a or an /// pointing to an SVG /// public Hotkey? Hotkey { get => GetValue(HotkeyProperty); set => SetValue(HotkeyProperty, value); } /// /// Gets or sets the watermark of the hotkey box when it is empty. /// public string? Watermark { get => GetValue(WatermarkProperty); set => SetValue(WatermarkProperty, value); } /// /// Gets or sets a boolean indicating whether the watermark should float above the hotkey box when it is not empty. /// public bool UseFloatingWatermark { get => GetValue(UseFloatingWatermarkProperty); set => SetValue(UseFloatingWatermarkProperty, value); } #endregion #region Events /// /// Occurs when the hotkey changes. /// public event TypedEventHandler? HotkeyChanged; #endregion }