mirror of
https://github.com/kwsch/pkNX.git
synced 2026-05-02 10:55:18 -05:00
162 lines
5.0 KiB
C#
162 lines
5.0 KiB
C#
using System;
|
|
using System.Globalization;
|
|
using System.Media;
|
|
using System.Text.RegularExpressions;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Input;
|
|
|
|
namespace pkNX.WinForms;
|
|
|
|
public enum NumericTextBoxMode
|
|
{
|
|
Integer,
|
|
Double,
|
|
}
|
|
|
|
public partial class NumericTextBox : TextBox
|
|
{
|
|
public static readonly DependencyProperty MinValueProperty =
|
|
DependencyProperty.Register(nameof(MinValue), typeof(double), typeof(NumericTextBox), new PropertyMetadata(double.NegativeInfinity));
|
|
|
|
public static readonly DependencyProperty MaxValueProperty =
|
|
DependencyProperty.Register(nameof(MaxValue), typeof(double), typeof(NumericTextBox), new PropertyMetadata(double.PositiveInfinity));
|
|
|
|
public static readonly DependencyProperty NumberModeProperty =
|
|
DependencyProperty.Register(nameof(NumberMode), typeof(NumericTextBoxMode), typeof(NumericTextBox), new PropertyMetadata(NumericTextBoxMode.Integer));
|
|
|
|
public static readonly DependencyProperty EvaluatedValueProperty =
|
|
DependencyProperty.Register(nameof(EvaluatedValue), typeof(double), typeof(NumericTextBox), new PropertyMetadata(0.0));
|
|
|
|
// Bind to Value Property
|
|
public static readonly DependencyProperty ValueProperty =
|
|
DependencyProperty.Register(nameof(Value), typeof(double), typeof(NumericTextBox), new PropertyMetadata(0.0, OnValueChanged));
|
|
|
|
// Use this to check for value changes
|
|
public event EventHandler EvaluatedValueChanged;
|
|
|
|
private readonly Regex doubleChars = RexexChar();
|
|
|
|
private readonly Regex intChars = RegexInt();
|
|
[GeneratedRegex(@"[^\d.\-*^%\+/()]+", RegexOptions.Compiled)] private static partial Regex RexexChar();
|
|
[GeneratedRegex(@"[^\d-*^%\+/()]+", RegexOptions.Compiled)] private static partial Regex RegexInt();
|
|
|
|
private static readonly string textFormat = "0.##";
|
|
|
|
public NumericTextBox()
|
|
{
|
|
SetResourceReference(StyleProperty, typeof(TextBox));
|
|
Text = EvaluatedValue.ToString(textFormat, CultureInfo.InvariantCulture);
|
|
|
|
PreviewTextInput += (obj, e) => e.Handled = !IsTextAllowed(e.Text);
|
|
PreviewKeyDown += OnPreviewKeyDown;
|
|
LostFocus += OnLostFocus;
|
|
TextChanged += OnTextChanged;
|
|
DataObject.AddPastingHandler(this, OnPasting);
|
|
}
|
|
|
|
private void OnPreviewKeyDown(object sender, KeyEventArgs e)
|
|
{
|
|
if (e.Key == Key.Enter)
|
|
{
|
|
TextBox t = (TextBox)sender;
|
|
t.FocusParent();
|
|
}
|
|
}
|
|
|
|
private Regex AllowedChars => NumberMode == NumericTextBoxMode.Double ? doubleChars : intChars;
|
|
|
|
public double MaxValue
|
|
{
|
|
get => (double)GetValue(MaxValueProperty);
|
|
set => SetValue(MaxValueProperty, value);
|
|
}
|
|
|
|
public double MinValue
|
|
{
|
|
get => (double)GetValue(MinValueProperty);
|
|
set => SetValue(MinValueProperty, value);
|
|
}
|
|
|
|
public double EvaluatedValue
|
|
{
|
|
get => (double)GetValue(EvaluatedValueProperty);
|
|
private set
|
|
{
|
|
var v = Math.Clamp(value, MinValue, MaxValue);
|
|
|
|
if (EvaluatedValue == v)
|
|
return;
|
|
|
|
SetValue(EvaluatedValueProperty, v);
|
|
EvaluatedValueChanged?.Invoke(this, EventArgs.Empty);
|
|
}
|
|
}
|
|
|
|
public double Value
|
|
{
|
|
get => (double)GetValue(ValueProperty);
|
|
set
|
|
{
|
|
var v = Math.Clamp(value, MinValue, MaxValue);
|
|
|
|
if (Value == v)
|
|
return;
|
|
|
|
SetValue(ValueProperty, v);
|
|
EvaluatedValue = v;
|
|
|
|
Text = Value.ToString(textFormat, CultureInfo.InvariantCulture);
|
|
}
|
|
}
|
|
|
|
public NumericTextBoxMode NumberMode
|
|
{
|
|
get => (NumericTextBoxMode)GetValue(NumberModeProperty);
|
|
set => SetValue(NumberModeProperty, value);
|
|
}
|
|
|
|
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
var minValue = (double)d.GetValue(MinValueProperty);
|
|
var maxValue = (double)d.GetValue(MaxValueProperty);
|
|
var v = Math.Clamp((double)e.NewValue, minValue, maxValue);
|
|
|
|
d.SetValue(TextProperty, v.ToString(textFormat, CultureInfo.InvariantCulture));
|
|
}
|
|
|
|
private bool IsTextAllowed(string text)
|
|
{
|
|
return !AllowedChars.IsMatch(text);
|
|
}
|
|
|
|
private void OnPasting(object sender, DataObjectPastingEventArgs e)
|
|
{
|
|
if (!e.DataObject.GetDataPresent(typeof(string)))
|
|
{
|
|
e.CancelCommand();
|
|
}
|
|
|
|
string text = (string)e.DataObject.GetData(typeof(string));
|
|
if (!IsTextAllowed(text))
|
|
{
|
|
SystemSounds.Beep.Play();
|
|
e.CancelCommand();
|
|
}
|
|
}
|
|
|
|
private void OnTextChanged(object sender, TextChangedEventArgs e)
|
|
{
|
|
if (StringToFormula.TryEval(Text, out double value))
|
|
EvaluatedValue = value;
|
|
}
|
|
|
|
private void OnLostFocus(object sender, RoutedEventArgs e)
|
|
{
|
|
if (StringToFormula.TryEval(Text, out double value))
|
|
Value = value;
|
|
else
|
|
Value = EvaluatedValue;
|
|
}
|
|
}
|