using System.Threading.Tasks; using Avalonia; using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Layout; namespace OpenNest.Avalonia { /// /// One number to set, as the WinForms SetValueForm: an "Increment :" box from 0 to a maximum /// shown with four decimals, an optional check box that disables the box, and a Set button /// that is also Enter. Esc or closing the window changes nothing. /// internal sealed class SetValueDialog : Window { public const double DefaultMaximum = 999999; /// What the user set: the value and the option check box. public sealed record Result(double Value, bool OptionChecked); private readonly NumericUpDown value; private readonly CheckBox option; // The last value the box held, which an emptied box keeps, as the WinForms box does. private double lastValid; private readonly double maximum; private SetValueDialog( string title, double initialValue, double maximum, string optionText, bool optionChecked) { Title = title; // Wide enough for the option's text on one line, as the WinForms form widens. MinWidth = 300; SizeToContent = SizeToContent.WidthAndHeight; CanResize = false; ShowInTaskbar = false; WindowStartupLocation = WindowStartupLocation.CenterOwner; this.maximum = maximum; lastValid = System.Math.Clamp(initialValue, 0, maximum); value = new NumericUpDown { Name = "Value", Minimum = 0, Maximum = (decimal)maximum, Increment = 1, // A typed value out of range goes to the nearest limit, as in WinForms, rather // than being refused. ClipValueToMinMax = true, FormatString = "0.0000", Value = (decimal)lastValid, HorizontalAlignment = HorizontalAlignment.Stretch, }; value.ValueChanged += (_, e) => { if (e.NewValue is { } v) lastValid = (double)v; }; var set = new Button { Name = "Set", Content = "Set", IsDefault = true }; set.Click += (_, _) => Close(new Result(Current, option.IsChecked == true)); var row = new Grid { ColumnDefinitions = new ColumnDefinitions("Auto,*,Auto"), ColumnSpacing = 8, }; var label = new TextBlock { Text = "Increment :", VerticalAlignment = VerticalAlignment.Center, }; row.Children.Add(label); Grid.SetColumn(value, 1); row.Children.Add(value); Grid.SetColumn(set, 2); row.Children.Add(set); option = new CheckBox { Name = "Option", Content = optionText, IsChecked = optionChecked, IsVisible = !string.IsNullOrEmpty(optionText), }; value.IsEnabled = !optionChecked; option.IsCheckedChanged += (_, _) => value.IsEnabled = option.IsChecked != true; var panel = new StackPanel { Margin = new Thickness(12), Spacing = 10 }; panel.Children.Add(row); panel.Children.Add(option); Content = panel; AddHandler(KeyDownEvent, (_, e) => { if (e.Key != Key.Escape) return; e.Handled = true; Close(null); }, RoutingStrategies.Tunnel); Opened += (_, _) => value.Focus(); } // A value out of range is taken to the nearest limit, as the WinForms box does. private double Current => System.Math.Clamp(lastValid, 0, maximum); /// /// The value and option the user set, or null when they closed the dialog without Set. /// public static Task ShowAsync( Window owner, string title, double value, double maximum = DefaultMaximum, string optionText = null, bool optionChecked = false) => new SetValueDialog(title, value, maximum, optionText, optionChecked) .ShowDialog(owner); } }