using System.Text; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Presenters; using Avalonia.Interactivity; namespace GSS2.Views; public partial class NumericKeyboardView : UserControl { public static readonly StyledProperty ValueProperty = AvaloniaProperty.Register(nameof(Value)); public double? Value { get => GetValue(ValueProperty); set => SetValue(ValueProperty, value); } public static readonly RoutedEvent ClosedEvent = RoutedEvent.Register(nameof(KeyboardClosed), RoutingStrategies.Bubble); public event EventHandler KeyboardClosed { add => AddHandler(ClosedEvent, value); remove => RemoveHandler(ClosedEvent, value); } private readonly TextPresenter? _presenter; private StringBuilder _text = new(); private bool changingValue = false; private int _cursor = 0; public NumericKeyboardView() { InitializeComponent(); ValueProperty.Changed.AddClassHandler((sender, value) => { if (sender != this) return; if (changingValue) return; if (value.NewValue is not double doubleValue) { changingValue = true; _text = new(); _cursor = _text.Length; changingValue = false; UpdateDisplay(); return; } changingValue = true; _text.Clear(); _text.Insert(0, doubleValue.ToString("G6").Replace(".", ",")); _cursor = _text.Length; changingValue = false; UpdateDisplay(); }); _presenter = this.FindControl("Text"); if (Value is not null) _text.Insert(0, Value.Value.ToString("G6").Replace(".", ",")); _cursor = _text.Length; _presenter?.ShowCaret(); UpdateDisplay(); } private void KeyPressed(object? sender, RoutedEventArgs e) { if (sender is not Button btn || btn.Content is not string symbol) return; if (symbol == "," && _cursor == 0) return; if (symbol == "," && _text.ToString().Contains(',')) { var index = _text.ToString().IndexOf(","); _text.Remove(index, 1); if (index < _cursor) _cursor--; } _text.Insert(_cursor, symbol); _cursor++; UpdateDisplay(); } private void Backspace(object? sender, RoutedEventArgs e) { if (_cursor > 0) { _cursor--; _text.Remove(_cursor, 1); UpdateDisplay(); } } private void MoveCursorLeft(object? sender, RoutedEventArgs e) { _cursor = Math.Max(0, _cursor - 1); UpdateDisplay(); } private void MoveCursorRight(object? sender, RoutedEventArgs e) { _cursor = Math.Min(_text.Length, _cursor + 1); UpdateDisplay(); } private void Accept(object? sender, RoutedEventArgs e) { if (double.TryParse(_text.ToString().Replace(",", "."), out double value)) Value = value; } private void Cancel(object? sender, RoutedEventArgs e) => Value = null; private void UpdateDisplay() { if (_presenter is null) return; _presenter.Text = _text.ToString(); _presenter.CaretIndex = _cursor; _presenter.InvalidateVisual(); if (double.TryParse(_text.ToString().Replace(",", "."), out double value)) Value = value; } }