mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-04-29 13:17:58 +03:00
241 lines
6.1 KiB
C#
241 lines
6.1 KiB
C#
![]() |
using System.Globalization;
|
|||
|
using System.Windows;
|
|||
|
using System.Windows.Controls;
|
|||
|
using System.Windows.Input;
|
|||
|
using TRX_ConfigToolLib.Utils;
|
|||
|
|
|||
|
namespace TRX_ConfigToolLib.Controls;
|
|||
|
|
|||
|
public partial class NumericUpDown : UserControl
|
|||
|
{
|
|||
|
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register
|
|||
|
(
|
|||
|
nameof(Value), typeof(decimal), typeof(NumericUpDown), new PropertyMetadata(decimal.MinValue, (sender, args) =>
|
|||
|
{
|
|||
|
if (sender is NumericUpDown numericUpDown)
|
|||
|
{
|
|||
|
numericUpDown.OnValueChanged();
|
|||
|
}
|
|||
|
})
|
|||
|
);
|
|||
|
|
|||
|
public static readonly DependencyProperty TextProperty = DependencyProperty.Register
|
|||
|
(
|
|||
|
nameof(Text), typeof(string), typeof(NumericUpDown), new PropertyMetadata(string.Empty)
|
|||
|
);
|
|||
|
|
|||
|
public static readonly DependencyProperty DecimalPlacesProperty = DependencyProperty.Register
|
|||
|
(
|
|||
|
nameof(DecimalPlaces), typeof(int), typeof(NumericUpDown), new PropertyMetadata(0, (sender, args) =>
|
|||
|
{
|
|||
|
if (sender is NumericUpDown numericUpDown)
|
|||
|
{
|
|||
|
numericUpDown.UpdateDisplayText();
|
|||
|
}
|
|||
|
})
|
|||
|
);
|
|||
|
|
|||
|
public static readonly DependencyProperty MinValueProperty = DependencyProperty.Register
|
|||
|
(
|
|||
|
nameof(MinValue), typeof(decimal), typeof(NumericUpDown), new PropertyMetadata(decimal.MinValue)
|
|||
|
);
|
|||
|
|
|||
|
public static readonly DependencyProperty MaxValueProperty = DependencyProperty.Register
|
|||
|
(
|
|||
|
nameof(MaxValue), typeof(decimal), typeof(NumericUpDown), new PropertyMetadata(decimal.MaxValue)
|
|||
|
);
|
|||
|
|
|||
|
public event EventHandler ValueChanged;
|
|||
|
|
|||
|
private bool _directValueSet;
|
|||
|
|
|||
|
private void OnValueChanged()
|
|||
|
{
|
|||
|
if (!_directValueSet)
|
|||
|
{
|
|||
|
UpdateDisplayText();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public decimal Value
|
|||
|
{
|
|||
|
get => (decimal)GetValue(ValueProperty);
|
|||
|
set
|
|||
|
{
|
|||
|
_directValueSet = true;
|
|||
|
SetValue(ValueProperty, Clamp(value));
|
|||
|
SetDisplayText();
|
|||
|
ValueChanged?.Invoke(this, EventArgs.Empty);
|
|||
|
_directValueSet = false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private bool _updateDisplayText;
|
|||
|
public string Text
|
|||
|
{
|
|||
|
get => (string)GetValue(TextProperty);
|
|||
|
set => SetValue(TextProperty, value);
|
|||
|
}
|
|||
|
|
|||
|
public int DecimalPlaces
|
|||
|
{
|
|||
|
get => (int)GetValue(DecimalPlacesProperty);
|
|||
|
set
|
|||
|
{
|
|||
|
SetValue(DecimalPlacesProperty, Math.Max(0, value));
|
|||
|
_stepSize = -1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private decimal _stepSize = -1;
|
|||
|
public decimal StepSize
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
if (_stepSize == -1)
|
|||
|
{
|
|||
|
_stepSize = (decimal)Math.Pow(10, DecimalPlaces * -1);
|
|||
|
}
|
|||
|
return _stepSize;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public decimal MinValue
|
|||
|
{
|
|||
|
get => (decimal)GetValue(MinValueProperty);
|
|||
|
set => SetValue(MinValueProperty, value);
|
|||
|
}
|
|||
|
|
|||
|
public decimal MaxValue
|
|||
|
{
|
|||
|
get => (decimal)GetValue(MaxValueProperty);
|
|||
|
set => SetValue(MaxValueProperty, value);
|
|||
|
}
|
|||
|
|
|||
|
public NumericUpDown()
|
|||
|
{
|
|||
|
InitializeComponent();
|
|||
|
_textBox.DataContext = this;
|
|||
|
}
|
|||
|
|
|||
|
private RelayCommand _spinUpCommand;
|
|||
|
public ICommand SpinUpCommand
|
|||
|
{
|
|||
|
get => _spinUpCommand ??= new RelayCommand(SpinUp, CanSpinUp);
|
|||
|
}
|
|||
|
|
|||
|
private void SpinUp()
|
|||
|
{
|
|||
|
AmendValue(StepSize);
|
|||
|
}
|
|||
|
|
|||
|
private bool CanSpinUp()
|
|||
|
{
|
|||
|
return Value < MaxValue;
|
|||
|
}
|
|||
|
|
|||
|
private RelayCommand _spinDownCommand;
|
|||
|
public ICommand SpinDownCommand
|
|||
|
{
|
|||
|
get => _spinDownCommand ??= new RelayCommand(SpinDown, CanSpinDown);
|
|||
|
}
|
|||
|
|
|||
|
private void SpinDown()
|
|||
|
{
|
|||
|
AmendValue(-StepSize);
|
|||
|
}
|
|||
|
|
|||
|
private bool CanSpinDown()
|
|||
|
{
|
|||
|
return Value > MinValue;
|
|||
|
}
|
|||
|
|
|||
|
private void AmendValue(decimal adjustment)
|
|||
|
{
|
|||
|
_updateDisplayText = true;
|
|||
|
Value += adjustment;
|
|||
|
_updateDisplayText = false;
|
|||
|
}
|
|||
|
|
|||
|
private decimal Clamp(decimal value)
|
|||
|
{
|
|||
|
value = Math.Round(value, DecimalPlaces);
|
|||
|
return Math.Min(MaxValue, Math.Max(MinValue, value));
|
|||
|
}
|
|||
|
|
|||
|
private void TextBox_Pasting(object sender, DataObjectPastingEventArgs e)
|
|||
|
{
|
|||
|
object data = e.DataObject.GetData(DataFormats.UnicodeText);
|
|||
|
if (!IsDataClean(data.ToString()))
|
|||
|
{
|
|||
|
e.CancelCommand();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void TextBox_TextInput(object sender, TextCompositionEventArgs e)
|
|||
|
{
|
|||
|
e.Handled = !IsDataClean(e.Text);
|
|||
|
}
|
|||
|
|
|||
|
private static bool IsDataClean(string data)
|
|||
|
{
|
|||
|
return decimal.TryParse(data, out decimal _)
|
|||
|
|| data == CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator
|
|||
|
|| data == CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator
|
|||
|
|| data == CultureInfo.CurrentCulture.NumberFormat.NegativeSign;
|
|||
|
}
|
|||
|
|
|||
|
private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
|
|||
|
{
|
|||
|
if (e.Key == Key.Up || e.Key == Key.Down)
|
|||
|
{
|
|||
|
decimal step = StepSize;
|
|||
|
if (Keyboard.IsKeyDown(Key.RightCtrl) || Keyboard.IsKeyDown(Key.LeftCtrl))
|
|||
|
{
|
|||
|
step *= 5;
|
|||
|
}
|
|||
|
if (e.Key == Key.Down)
|
|||
|
{
|
|||
|
step *= -1;
|
|||
|
}
|
|||
|
|
|||
|
AmendValue(step);
|
|||
|
}
|
|||
|
else if (e.Key == Key.Enter)
|
|||
|
{
|
|||
|
UpdateDisplayText();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
|
|||
|
{
|
|||
|
if (!_updateDisplayText
|
|||
|
&& sender is TextBox textBox
|
|||
|
&& decimal.TryParse(textBox.Text, out decimal val)
|
|||
|
&& val >= MinValue && val <= MaxValue)
|
|||
|
{
|
|||
|
Value = val;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
|
|||
|
{
|
|||
|
UpdateDisplayText();
|
|||
|
}
|
|||
|
|
|||
|
private void UpdateDisplayText()
|
|||
|
{
|
|||
|
_updateDisplayText = true;
|
|||
|
SetDisplayText();
|
|||
|
_updateDisplayText = false;
|
|||
|
}
|
|||
|
|
|||
|
private void SetDisplayText()
|
|||
|
{
|
|||
|
if (_updateDisplayText)
|
|||
|
{
|
|||
|
Text = Value.ToString("F" + DecimalPlaces.ToString(CultureInfo.CurrentCulture), CultureInfo.CurrentCulture);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|