using InABox.Core; using Syncfusion.Windows.Shared; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace InABox.DynamicGrid { public class CoreTimeEditorControl : DynamicEnclosedEditorControl { private Grid Grid; private DateTimeEdit Start; private TimeSpanEdit Duration; private DateTimeEdit Finish; private CoreTime Time = new(); protected override FrameworkElement CreateEditor() { Grid = new Grid(); Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); Start = CreateTimeEdit("Start:", 0, StartChanged, false); Duration = CreateTimeSpanEdit("Duration:", 4, DurationChanged, true); Finish = CreateTimeEdit("Finish:", 8, FinishChanged, true); return Grid; } private void StartChanged(TimeSpan start) { Time.Start = start; UpdateEditors(); } private void DurationChanged(TimeSpan duration) { Time.Duration = duration; UpdateEditors(); } private void FinishChanged(TimeSpan finish) { Time.Finish = finish; UpdateEditors(); } private void UpdateEditors() { SetValue(Start, Time.Start); SetValue(Duration, Time.Duration); SetValue(Finish, Time.Finish); CheckChanged(); } private TimeSpanEdit CreateTimeSpanEdit(string header, int column, Action onChanged, bool leftMargin) { var label = new Label { Content = header, Margin = new Thickness(leftMargin ? 5 : 0, 0, 0, 0) }; label.SetValue(Grid.ColumnProperty, column); var edit = new TimeSpanEdit { Format = "h:mm", MinValue = new TimeSpan(), MaxValue = TimeSpan.MaxValue, VerticalAlignment = VerticalAlignment.Stretch, VerticalContentAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Stretch, HorizontalContentAlignment = HorizontalAlignment.Center, ShowArrowButtons = false }; edit.SetValue(Grid.ColumnProperty, column + 1); edit.PreviewKeyDown += (o, e) => { var separator = edit.Text.IndexOf(":"); if (e.Key == Key.OemPeriod) { edit.Select(separator + 1, 2); e.Handled = true; } else if (e.Key == Key.Back) { if (string.Equals(edit.SelectedText, "00")) edit.Select(0, separator); else edit.SelectedText = "00"; e.Handled = true; } else if (e.Key == Key.Tab) { if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.LeftShift)) { if (edit.SelectionStart > separator) { edit.Select(0, separator); e.Handled = true; } } else { if (edit.SelectionLength != edit.Text.Length && edit.SelectionStart < separator) { edit.Select(separator + 1, 2); e.Handled = true; } } } }; var changed = false; edit.ValueChanged += (o, e) => { changed = true; }; edit.LostFocus += (o, e) => { if (changed) onChanged(GetValue(edit)); }; var less = new Button { Content = "<", Width = 23, Margin = new Thickness(2, 0, 0, 0), Focusable = false }; less.SetValue(Grid.ColumnProperty, column + 2); less.Click += (o, e) => { edit.Value = edit.Value.HasValue && edit.Value >= new TimeSpan(0, 15, 0) ? edit.Value.Value.Subtract(new TimeSpan(0, 15, 0)) : new TimeSpan(0); onChanged(GetValue(edit)); }; var more = new Button { Content = ">", Width = 23, Margin = new Thickness(2, 0, 0, 0), Focusable = false }; more.SetValue(Grid.ColumnProperty, column + 3); more.Click += (o, e) => { edit.Value = edit.Value.HasValue ? edit.Value.Value.Add(new TimeSpan(0, 15, 0)) : new TimeSpan(0, 15, 0); onChanged(GetValue(edit)); }; Grid.Children.Add(label); Grid.Children.Add(more); Grid.Children.Add(less); Grid.Children.Add(edit); return edit; } private DateTimeEdit CreateTimeEdit(string header, int column, Action onChanged, bool leftMargin) { var label = new Label { Content = header, Margin = new Thickness(leftMargin ? 5 : 0, 0, 0, 0) }; label.SetValue(Grid.ColumnProperty, column); var edit = new DateTimeEdit { Pattern = DateTimePattern.CustomPattern, CustomPattern = "HH:mm", //DateTimeFormat.Custom, //FormatString = "HH:mm", VerticalAlignment = VerticalAlignment.Stretch, VerticalContentAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Stretch, HorizontalContentAlignment = HorizontalAlignment.Center, //TimeInterval = new TimeSpan(0, 15, 0), //ShowButtonSpinner = false DropDownView = DropDownViews.Clock, IsButtonPopUpEnabled = false }; edit.SetValue(Grid.ColumnProperty, column + 1); edit.PreviewKeyDown += (o, e) => { var separator = edit.Text.IndexOf(":"); if (e.Key == Key.OemPeriod) { edit.Select(separator + 1, 2); e.Handled = true; } else if (e.Key == Key.Back) { if (string.Equals(edit.SelectedText, "00")) edit.Select(0, separator); else edit.SelectedText = "00"; e.Handled = true; } else if (e.Key == Key.Tab) { if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.LeftShift)) { if (edit.SelectionStart > separator) { edit.Select(0, separator); e.Handled = true; } } else { if (edit.SelectionLength != edit.Text.Length && edit.SelectionStart < separator) { edit.Select(separator + 1, 2); e.Handled = true; } } } }; var changed = false; edit.DateTimeChanged += (o, e) => { changed = true; }; edit.LostFocus += (o, e) => { if (changed) { onChanged(GetValue(edit)); } }; var less = new Button { Content = "<", Width = 23, Margin = new Thickness(2, 0, 0, 0), Focusable = false }; less.SetValue(Grid.ColumnProperty, column + 2); less.Click += (o, e) => { edit.DateTime = edit.DateTime.HasValue && edit.DateTime.Value.TimeOfDay >= new TimeSpan(0, 15, 0) ? edit.DateTime.Value.Subtract(new TimeSpan(0, 15, 0)) : edit.DateTime; onChanged(GetValue(edit)); }; var more = new Button { Content = ">", Width = 23, Margin = new Thickness(2, 0, 0, 0), Focusable = false }; more.SetValue(Grid.ColumnProperty, column + 3); more.Click += (o, e) => { edit.DateTime = edit.DateTime.HasValue && edit.DateTime.Value.TimeOfDay < new TimeSpan(23, 45, 0) ? edit.DateTime.Value.Add(new TimeSpan(0, 15, 0)) : edit.DateTime; onChanged(GetValue(edit)); }; Grid.Children.Add(label); Grid.Children.Add(edit); Grid.Children.Add(less); Grid.Children.Add(more); return edit; } private static TimeSpan GetValue(DateTimeEdit edit) { var result = new TimeSpan(0); if (edit.DateTime.HasValue) result = edit.DateTime.Value.TimeOfDay; result = new TimeSpan(result.Hours, result.Minutes, 0); return result; } private static void SetValue(DateTimeEdit edit, TimeSpan value) { if (value.Ticks > 0) edit.DateTime = DateTime.MinValue.Add(value); else edit.DateTime = null; } private static TimeSpan GetValue(TimeSpanEdit edit) { var result = new TimeSpan(0); if (edit.Value.HasValue) result = edit.Value.Value; return result; } private static void SetValue(TimeSpanEdit edit, TimeSpan value) { edit.Value = value; } public override int DesiredHeight() { return 25; } public override int DesiredWidth() { return int.MaxValue; } public override Dictionary GetValues() { return new Dictionary { { $"{ColumnName}.Start", Time.Start }, { $"{ColumnName}.Duration", Time.Duration }, { $"{ColumnName}.Finish", Time.Finish } }; } public override object? GetValue(string property) { if (!property.StartsWith($"{ColumnName}.")) return null; property = property[(ColumnName.Length + 1)..]; if (property == "Start") return Time.Start; if (property == "Duration") return Time.Duration; if (property == "Finish") return Time.Finish; return null; } public override void SetValue(string property, object? value) { if (!property.StartsWith($"{ColumnName}.")) return; property = property[(ColumnName.Length + 1)..]; if (value is not TimeSpan timeSpan) return; if (property == "Start") Time.Start = timeSpan; else if (property == "Duration") Time.Duration = timeSpan; else if (property == "Finish") Time.Finish = timeSpan; UpdateEditors(); } public override void SetColor(Color color) { Start.Background = new SolidColorBrush(color); Duration.Background = new SolidColorBrush(color); Finish.Background = new SolidColorBrush(color); } public override void SetFocus() { Start.Focus(); } } }