using Comal.Classes; using InABox.Clients; using InABox.Core; using InABox.DynamicGrid; using InABox.Wpf; using InABox.WPF; using Syncfusion.Data; using Syncfusion.UI.Xaml.Grid; using Syncfusion.Windows.Shared; using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Media; namespace PRSDesktop; public class JobRequisitionItemSelectionItem : BaseObject { public double Quantity { get; set; } private double _issued; public double Issued { get => _issued; set { var oldValue = _issued; var canMinus = CanMinus; var canPlus = CanPlus; _issued = value; if(oldValue != value) { OnPropertyChanged(nameof(Issued), oldValue, value); } if(canMinus != CanMinus) { OnPropertyChanged(nameof(CanMinus), canMinus, CanMinus); } if(canPlus != CanPlus) { OnPropertyChanged(nameof(CanPlus), canPlus, CanPlus); } } } public double MaxValue { get; set; } private bool _editable = true; public bool Editable { get => _editable; set { var oldValue = _editable; var canMinus = CanMinus; var canPlus = CanPlus; _editable = value; if(oldValue != value) { OnPropertyChanged(nameof(Editable), oldValue, value); } if(canMinus != CanMinus) { OnPropertyChanged(nameof(CanMinus), canMinus, CanMinus); } if(canPlus != CanPlus) { OnPropertyChanged(nameof(CanPlus), canPlus, CanPlus); } } } public bool CanMinus => Editable && Issued > 0; public bool CanPlus => Editable && Issued < MaxValue; public JobRequisitionItem JRI { get; set; } } public abstract class JobRequisitionItemSelectionGrid : DynamicItemsListGrid, INotifyPropertyChanged where T : JobRequisitionItemSelectionItem, new() { private double _totalQuantity; public double TotalQuantity { get => _totalQuantity; set { _totalQuantity = value; OnPropertyChanged(); } } private double _totalIssued; public double TotalIssued { get => _totalIssued; set { _totalIssued = value; OnPropertyChanged(); } } private bool _observing = true; public void SetObserving(bool observing) { if(_observing != observing) { _observing = observing; if (_observing) { Recalculate(); } } } protected override void Init() { base.Init(); ActionColumns.Add(new DynamicTemplateColumn(TotalColumn_Template) { HeaderText = "Total", Width = 60, GetSummary = () => { var summary = new GridSummaryColumn { TemplateSelector = new FuncTemplateSelector((item, o) => TotalQuantity_Template()) }; return summary; } }); ActionColumns.Add(new DynamicTemplateColumn(QuantityColumn_Template) { HeaderText = "Quantity", Width = 230, GetSummary = () => { var summary = new GridSummaryColumn { TemplateSelector = new FuncTemplateSelector((item, o) => TotalIssued_Template()) }; return summary; } }); } protected override void DoReconfigure(DynamicGridOptions options) { base.DoReconfigure(options); options.Clear(); } private FrameworkElement TotalQuantity_Template() { var quantity = new DoubleTextBox { HorizontalContentAlignment = HorizontalAlignment.Center, VerticalContentAlignment = VerticalAlignment.Center, VerticalAlignment = VerticalAlignment.Stretch, HorizontalAlignment = HorizontalAlignment.Stretch, Background = new SolidColorBrush(Colors.WhiteSmoke), IsReadOnly = true, Margin = new Thickness(0, 5, 0, 5) }; quantity.Bind(DoubleTextBox.ValueProperty, this, x => x.TotalQuantity); return quantity; } private FrameworkElement TotalIssued_Template() { var quantity = new DoubleTextBox { HorizontalContentAlignment = HorizontalAlignment.Center, VerticalContentAlignment = VerticalAlignment.Center, VerticalAlignment = VerticalAlignment.Stretch, HorizontalAlignment = HorizontalAlignment.Stretch, Background = new SolidColorBrush(Colors.LightGreen), IsReadOnly = true, Margin = new Thickness(50 + 30 + 10, 5, 50 + 30 + 5, 5) }; quantity.Bind(DoubleTextBox.ValueProperty, this, x => x.TotalIssued); return quantity; } private class TotalAggregate : ISummaryAggregate { public double Sum { get; private set; } private JobRequisitionItemSelectionGrid Grid; public enum TotalColumn { Quantity, Issued } public TotalColumn Type { get; set; } public TotalAggregate(TotalColumn type, JobRequisitionItemSelectionGrid grid) { Type = type; Grid = grid; } public Action CalculateAggregateFunc() { return AggregateFunc; } private void AggregateFunc(IEnumerable items, string property, PropertyDescriptor args) { if (items is IEnumerable rows) { Sum = Type switch { TotalColumn.Quantity => Grid.TotalQuantity, TotalColumn.Issued or _ => Grid.TotalIssued }; } else { Logger.Send(LogType.Error, "", $"Attempting to calculate aggregate on invalid data type '{items.GetType()}'."); } } } protected class UIComponent : DynamicGridGridUIComponent { public UIComponent(JobRequisitionItemSelectionGrid grid) { Parent = grid; GridLines = DynamicGridLines.None; RowHeight = 40; HeaderRowHeight = 40; } protected override Brush? GetCellSelectionBackgroundBrush() { return null; } protected override Brush? GetCellSelectionForegroundBrush() { return null; } protected override Brush? GetCellBackground(CoreRow row, DynamicColumnBase column) { return base.GetCellBackground(row, column); } protected override Style GetHeaderCellStyle(DynamicColumnBase column) { var style = base.GetHeaderCellStyle(column); style.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.Silver))); style.Setters.Add(new Setter(Control.FontWeightProperty, FontWeights.Bold)); style.Setters.Add(new Setter(Control.BorderThicknessProperty, new Thickness(0.0))); style.Setters.Add(new Setter(Control.MarginProperty, new Thickness(0.0))); return style; } protected override Style GetSummaryRowStyle() { var style = base.GetSummaryRowStyle(); style.Setters.Add(new Setter(Control.BorderBrushProperty, new SolidColorBrush(Colors.Silver))); style.Setters.Add(new Setter(Control.BorderThicknessProperty, new Thickness(1, 1, 0, 1))); style.Setters.Add(new Setter(Control.MarginProperty, new Thickness(0, 1, 0, 0))); style.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.WhiteSmoke))); return style; } protected override Style GetSummaryCellStyle(DynamicColumnBase column) { var style = base.GetSummaryCellStyle(column); style.Setters.Add(new Setter(Control.BorderThicknessProperty, new Thickness(0))); style.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.Transparent))); style.Setters.Add(new Setter(GridTableSummaryCell.HorizontalContentAlignmentProperty, HorizontalAlignment.Stretch)); style.Setters.Add(new Setter(Control.VerticalContentAlignmentProperty, VerticalAlignment.Stretch)); style.Setters.Add(new Setter(Control.PaddingProperty, new Thickness(0))); return style; } } protected override IDynamicGridUIComponent CreateUIComponent() { return new UIComponent(this); } private FrameworkElement? TotalColumn_Template(CoreRow row) { var item = LoadItem(row); var quantity = new DoubleTextBox { HorizontalContentAlignment = HorizontalAlignment.Center, VerticalContentAlignment = VerticalAlignment.Center, VerticalAlignment = VerticalAlignment.Stretch, Background = new SolidColorBrush(Colors.WhiteSmoke), IsReadOnly = true, Margin = new Thickness(0, 5, 0, 5) }; quantity.Bind(DoubleTextBox.ValueProperty, item, x => x.Quantity); quantity.Bind(Button.IsEnabledProperty, item, x => x.Editable); return quantity; } private FrameworkElement? QuantityColumn_Template(CoreRow row) { var item = LoadItem(row); var grid = new Grid(); grid.Margin = new Thickness(5); grid.AddColumn(50); grid.AddColumn(30); grid.AddColumn(60); grid.AddColumn(30); grid.AddColumn(50); var none = new Button { Content = "None", }; none.Bind(Button.IsEnabledProperty, item, x => x.Editable); none.Margin = new Thickness(0); none.Click += (o, e) => None_Click(item); grid.AddChild(none, 0, 0); var minus = new Button { Content = "-", }; minus.Bind(Button.IsEnabledProperty, item, x => x.CanMinus); minus.Margin = new Thickness(5, 0, 0, 0); minus.Click += (o, e) => Minus_Click(item); grid.AddChild(minus, 0, 1); var quantity = new DoubleTextBox { HorizontalContentAlignment = HorizontalAlignment.Center, VerticalContentAlignment = VerticalAlignment.Center, VerticalAlignment = VerticalAlignment.Stretch, Margin = new Thickness(5, 0, 0, 0) }; var style = new Style(typeof(DoubleTextBox)); style.AddSetter(BackgroundProperty, Colors.LightYellow.ToBrush()); style.AddDataTrigger() .Bind(item, x => x.Issued, true, new FuncConverter(issued => issued > item.Quantity && issued > 0)) .AddSetter(BackgroundProperty, Colors.Salmon.ToBrush()); quantity.Style = style; quantity.Bind(DoubleTextBox.ValueProperty, item, x => x.Issued); quantity.MinValue = 0; quantity.Bind(DoubleTextBox.MaxValueProperty, item, x => x.MaxValue); quantity.Bind(Button.IsEnabledProperty, item, x => x.Editable); grid.AddChild(quantity, 0, 2); var plus = new Button { Content = "+", }; plus.Bind(Button.IsEnabledProperty, item, x => x.CanPlus); plus.Margin = new Thickness(5, 0, 0, 0); plus.Click += (o, e) => Plus_Click(item); grid.AddChild(plus, 0, 3); var all = new Button { Content = "All", }; all.Bind(Button.IsEnabledProperty, item, x => x.Editable); all.Margin = new Thickness(5, 0, 0, 0); all.Click += (o, e) => All_Click(item); grid.AddChild(all, 0, 4); return grid; } private void None_Click(T item) { item.Issued = 0; } private void Minus_Click(T item) { item.Issued = Math.Max(0, item.Issued - 1); } private void Plus_Click(T item) { item.Issued = Math.Min(item.Issued + 1, item.MaxValue); } private void All_Click(T item) { item.Issued = Math.Max(0, item.Quantity); } protected override void Reload(Filters criteria, Columns columns, ref SortOrder? sort, Action action) { foreach(var item in Items) { item.PropertyChanged += (o, e) => Recalculate(); } Recalculate(); base.Reload(criteria, columns, ref sort, action); } public Dictionary GetQuantities() { return Items.ToDictionary(x => x.JRI.ID, x => x.Issued); } private void Recalculate() { if (!_observing) return; TotalQuantity = Items.Sum(x => x.Quantity); TotalIssued = Items.Sum(x => x.Issued); } public event PropertyChangedEventHandler? PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }