From 4ec98cfab14f4e2c8cd1ba246c85e75ea67d1934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tiago=20Concei=C3=A7=C3=A3o?= Date: Sun, 21 Feb 2021 03:38:37 +0000 Subject: [PATCH] v2.5.0 * (Add) Help - Material manager (F10): Allow to manage material stock and costs with statistic over time * (Add) File - I printed this file (CTRL + P): Allow to select a material and consume resin from stock and print time from the loaded file --- CHANGELOG.md | 5 + UVtools.Core/Managers/MaterialManager.cs | 271 ++++++++++++++++++ UVtools.Core/Objects/Material.cs | 99 +++++-- .../Operations/OperationIPrintedThisFile.cs | 138 +++++++++ UVtools.Core/UVtools.Core.csproj | 4 +- UVtools.WPF/App.axaml.cs | 4 + UVtools.WPF/Assets/Icons/flask-16x16.png | Bin 0 -> 162 bytes .../Tools/ToolIPrintedThisFileControl.axaml | 53 ++++ .../ToolIPrintedThisFileControl.axaml.cs | 21 ++ UVtools.WPF/MainWindow.axaml | 21 ++ UVtools.WPF/MainWindow.axaml.cs | 17 +- UVtools.WPF/UVtools.WPF.csproj | 7 +- .../Windows/MaterialManagerWindow.axaml | 254 ++++++++++++++++ .../Windows/MaterialManagerWindow.axaml.cs | 97 +++++++ ...r.axaml => PrusaSlicerManagerWindow.axaml} | 2 +- ...l.cs => PrusaSlicerManagerWindow.axaml.cs} | 4 +- 16 files changed, 967 insertions(+), 30 deletions(-) create mode 100644 UVtools.Core/Managers/MaterialManager.cs create mode 100644 UVtools.Core/Operations/OperationIPrintedThisFile.cs create mode 100644 UVtools.WPF/Assets/Icons/flask-16x16.png create mode 100644 UVtools.WPF/Controls/Tools/ToolIPrintedThisFileControl.axaml create mode 100644 UVtools.WPF/Controls/Tools/ToolIPrintedThisFileControl.axaml.cs create mode 100644 UVtools.WPF/Windows/MaterialManagerWindow.axaml create mode 100644 UVtools.WPF/Windows/MaterialManagerWindow.axaml.cs rename UVtools.WPF/Windows/{PrusaSlicerManager.axaml => PrusaSlicerManagerWindow.axaml} (99%) rename UVtools.WPF/Windows/{PrusaSlicerManager.axaml.cs => PrusaSlicerManagerWindow.axaml.cs} (96%) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9999cb..38ceaba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 21/02/2021 - v2.5.0 + +* (Add) Help - Material manager (F10): Allow to manage material stock and costs with statistic over time +* (Add) File - I printed this file (CTRL + P): Allow to select a material and consume resin from stock and print time from the loaded file + ## 19/02/2021 - v2.4.9 * **(Fix) PhotonWorkshop files: (#149)** diff --git a/UVtools.Core/Managers/MaterialManager.cs b/UVtools.Core/Managers/MaterialManager.cs new file mode 100644 index 0000000..bd0446b --- /dev/null +++ b/UVtools.Core/Managers/MaterialManager.cs @@ -0,0 +1,271 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Xml.Serialization; +using UVtools.Core.Objects; + +namespace UVtools.Core.Managers +{ + public class MaterialManager : BindableBase, IList + { + #region Settings + + public static string FilePath; + #endregion + + #region Singleton + + private static Lazy _instanceHolder = + new(() => new MaterialManager()); + + /// + /// Instance of (singleton) + /// + public static MaterialManager Instance => _instanceHolder.Value; + + //public static List Operations => _instance.Operations; + #endregion + + #region Members + + private ObservableCollection _materials = new(); + + #endregion + + #region Properties + + public ObservableCollection Materials + { + get => _materials; + set => RaiseAndSetIfChanged(ref _materials, value); + } + + /// + /// Gets the total number of bottles in stock + /// + public int BottlesInStock => this.Sum(material => material.BottlesInStock); + + /// + /// Gets the total number of bottles ever owned + /// + public int OwnedBottles => this.Sum(material => material.OwnedBottles); + + /// + /// Gets the total of consumed volume in milliliters + /// + public decimal ConsumedVolume => this.Sum(material => material.ConsumedVolume); + + /// + /// Gets the total of consumed volume in liters + /// + public decimal ConsumedVolumeLiters => this.Sum(material => material.ConsumedVolumeLiters); + + /// + /// Gets the total volume in stock in milliliters + /// + public decimal VolumeInStock => this.Sum(material => material.VolumeInStock); + + /// + /// Gets the total volume in stock in liters + /// + public decimal VolumeInStockLiters => VolumeInStock / 1000; + + /// + /// Gets the total costs + /// + public decimal TotalCost => this.Sum(material => material.TotalCost); + + /// + /// Gets the total print time in hours + /// + public double PrintTime => this.Sum(material => material.PrintTime); + + /// + /// Gets the total print time + /// + public TimeSpan PrintTimeSpan => TimeSpan.FromHours(PrintTime); + + #endregion + + #region Constructor + private MaterialManager() + { + } + #endregion + + #region Methods + public Material this[int index] + { + get => _materials[index]; + set => _materials[index] = value; + } + + public Material this[uint index] + { + get => _materials[(int) index]; + set => _materials[(int) index] = value; + } + + public Material this[Material material] + { + get + { + var index = IndexOf(material); + return index < 0 ? this[index] : null; + } + set + { + var index = IndexOf(material); + if(index >= 0) this[index] = value; + } + } + + public IEnumerator GetEnumerator() => _materials.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public void Add(Material item) + { + _materials.Add(item); + RaisePropertiesChanged(); + } + + public void Add(Material item, bool save) + { + Add(item); + if (save) Save(); + } + + public void Clear() + { + _materials.Clear(); + RaisePropertiesChanged(); + } + + public void Clear(bool save) + { + Clear(); + if(save) Save(); + } + + + public bool Contains(Material item) => _materials.Contains(item); + + public void CopyTo(Material[] array, int arrayIndex) + { + _materials.CopyTo(array, arrayIndex); + RaisePropertiesChanged(); + } + + public bool Remove(Material item) + { + if (_materials.Remove(item)) + { + RaisePropertiesChanged(); + return true; + } + + return false; + } + + public void Remove(Material item, bool save) + { + Remove(item); + if (save) Save(); + } + + public int Count => _materials.Count; + public bool IsReadOnly => false; + public int IndexOf(Material item) => _materials.IndexOf(item); + + public void Insert(int index, Material item) + { + _materials.Insert(index, item); + RaisePropertiesChanged(); + } + + public void Insert(int index, Material item, bool save) + { + Insert(index, item); + if (save) Save(); + } + + public void RemoveAt(int index) + { + _materials.RemoveAt(index); + RaisePropertiesChanged(); + } + + public void RemoveAt(int index, bool save) + { + RemoveAt(index); + if (save) Save(); + } + + public void RaisePropertiesChanged() + { + RaisePropertyChanged(nameof(BottlesInStock)); + RaisePropertyChanged(nameof(OwnedBottles)); + RaisePropertyChanged(nameof(ConsumedVolume)); + RaisePropertyChanged(nameof(ConsumedVolumeLiters)); + RaisePropertyChanged(nameof(VolumeInStock)); + RaisePropertyChanged(nameof(VolumeInStockLiters)); + RaisePropertyChanged(nameof(TotalCost)); + RaisePropertyChanged(nameof(PrintTime)); + RaisePropertyChanged(nameof(PrintTimeSpan)); + RaisePropertyChanged(nameof(Count)); + } + + /// + /// Load settings from file + /// + public static void Load() + { + if (string.IsNullOrWhiteSpace(FilePath) || !File.Exists(FilePath)) + { + return; + } + + var serializer = new XmlSerializer(Instance.GetType()); + try + { + using var myXmlReader = new StreamReader(FilePath); + var instance = (MaterialManager)serializer.Deserialize(myXmlReader); + _instanceHolder = new Lazy(() => instance); + } + catch (Exception e) + { + Debug.WriteLine(e.ToString()); + } + } + + /// + /// Save settings to file + /// + public static void Save() + { + var serializer = new XmlSerializer(Instance.GetType()); + try + { + using var myXmlWriter = new StreamWriter(FilePath); + serializer.Serialize(myXmlWriter, Instance); + } + catch (Exception e) + { + Debug.WriteLine(e.ToString()); + } + } + + #endregion + + public void SortByName() + { + var materials = _materials.ToList(); + materials.Sort((material, material1) => string.Compare(material.Name, material1.Name, StringComparison.Ordinal)); + Materials = new ObservableCollection(materials); + } + } +} \ No newline at end of file diff --git a/UVtools.Core/Objects/Material.cs b/UVtools.Core/Objects/Material.cs index fed7392..84f39fa 100644 --- a/UVtools.Core/Objects/Material.cs +++ b/UVtools.Core/Objects/Material.cs @@ -13,17 +13,17 @@ namespace UVtools.Core.Objects /// /// Represents a material to feed in the printer /// - public class Material : BindableBase + public class Material : BindableBase, ICloneable { #region Members private string _name; - private decimal _bottleVolume = 1000; + private uint _bottleVolume = 1000; private decimal _density = 1; private decimal _bottleCost = 30; private int _bottlesInStock = 1; private decimal _bottleRemainingVolume = 1000; - private decimal _totalConsumedVolume; - private double _totalPrintTime; + private decimal _consumedVolume; + private double _printTime; #endregion @@ -37,14 +37,16 @@ namespace UVtools.Core.Objects /// /// Gets or sets the bottle volume in milliliters /// - public decimal BottleVolume + public uint BottleVolume { get => _bottleVolume; set { if(!RaiseAndSetIfChanged(ref _bottleVolume, value)) return; RaisePropertyChanged(nameof(BottleWeight)); - RaisePropertyChanged(nameof(TotalConsumedBottles)); + RaisePropertyChanged(nameof(ConsumedBottles)); + RaisePropertyChanged(nameof(TotalCost)); + RaisePropertyChanged(nameof(VolumeInStock)); } } @@ -72,16 +74,28 @@ namespace UVtools.Core.Objects public decimal BottleCost { get => _bottleCost; - set => RaiseAndSetIfChanged(ref _bottleCost, value); + set + { + if(!RaiseAndSetIfChanged(ref _bottleCost, value)) return; + RaisePropertyChanged(nameof(TotalCost)); + } } + public decimal TotalCost => OwnedBottles * _bottleCost; + /// /// Gets or sets the number of bottles in stock /// public int BottlesInStock { get => _bottlesInStock; - set => RaiseAndSetIfChanged(ref _bottlesInStock, value); + set + { + if(!RaiseAndSetIfChanged(ref _bottlesInStock, value)) return; + RaisePropertyChanged(nameof(OwnedBottles)); + RaisePropertyChanged(nameof(TotalCost)); + RaisePropertyChanged(nameof(VolumeInStock)); + } } /// @@ -89,47 +103,75 @@ namespace UVtools.Core.Objects /// public decimal BottleRemainingVolume { - get => _bottleRemainingVolume; - set => RaiseAndSetIfChanged(ref _bottleRemainingVolume, value); + get => Math.Round(_bottleRemainingVolume, 2); + set + { + if(!RaiseAndSetIfChanged(ref _bottleRemainingVolume, value)) return; + RaisePropertyChanged(nameof(VolumeInStock)); + } } + /// + /// Gets the total available volume in stock in milliliters + /// + public decimal VolumeInStock => _bottlesInStock * _bottleVolume - (_bottleVolume - _bottleRemainingVolume); + /// /// Gets the number of consumed bottles /// - public uint TotalConsumedBottles => (uint) Math.Floor(_totalConsumedVolume / _bottleVolume); + public uint ConsumedBottles => (uint) Math.Floor(_consumedVolume / _bottleVolume); + + /// + /// Gets the total number of owned bottles + /// + public int OwnedBottles => (int) (_bottlesInStock + ConsumedBottles); /// /// Gets or sets the total number of consumed volume in milliliters /// - public decimal TotalConsumedVolume + public decimal ConsumedVolume { - get => _totalConsumedVolume; - set => RaiseAndSetIfChanged(ref _totalConsumedVolume, value); + get => _consumedVolume; + set + { + if(!RaiseAndSetIfChanged(ref _consumedVolume, value)) return; + RaisePropertyChanged(nameof(ConsumedVolumeLiters)); + } } + /// + /// Gets total number of consumed volume in liters + /// + public decimal ConsumedVolumeLiters => ConsumedVolume / 1000; + /// /// Gets or sets the total print time using with material in hours /// - public double TotalPrintTime + public double PrintTime { - get => _totalPrintTime; - set => RaiseAndSetIfChanged(ref _totalPrintTime, value); + get => _printTime; + set + { + if(!RaiseAndSetIfChanged(ref _printTime, value)) return; + RaisePropertyChanged(nameof(PrintTimeSpan)); + } } - public TimeSpan TotalPrintTimeSpan => TimeSpan.FromHours(_totalPrintTime); + public TimeSpan PrintTimeSpan => TimeSpan.FromHours(_printTime); #endregion #region Constructors public Material() { } - public Material(string name, decimal bottleVolume = 1000, decimal density = 1, decimal bottleCost = 30, int bottlesInStock = 1) + public Material(string name, uint bottleVolume = 1000, decimal density = 1, decimal bottleCost = 30, int bottlesInStock = 1) { _name = name; _bottleVolume = bottleVolume; _density = density; _bottleCost = bottleCost; _bottlesInStock = bottlesInStock; + _bottleRemainingVolume = bottleVolume; } #endregion @@ -155,7 +197,17 @@ namespace UVtools.Core.Objects public override string ToString() { - return $"{nameof(Name)}: {Name}, {nameof(BottleVolume)}: {BottleVolume}ml, {nameof(BottleWeight)}: {BottleWeight}g, {nameof(Density)}: {Density}g/ml, {nameof(BottleCost)}: {BottleCost}, {nameof(BottlesInStock)}: {BottlesInStock}, {nameof(BottleRemainingVolume)}: {BottleRemainingVolume}ml, {nameof(TotalConsumedBottles)}: {TotalConsumedBottles}, {nameof(TotalConsumedVolume)}: {TotalConsumedVolume}ml, {nameof(TotalPrintTime)}: {TotalPrintTime:F4}h"; + return $"{_name} ({_bottleRemainingVolume}/{VolumeInStock}ml)"; + } + + public object Clone() + { + return MemberwiseClone(); + } + + public Material CloneMaterial() + { + return (Material)Clone(); } #endregion @@ -200,8 +252,9 @@ namespace UVtools.Core.Objects } BottlesInStock -= consumedBottles; + ConsumedVolume += volume; - AddPrintTime(printSeconds); + AddPrintTimeSeconds(printSeconds); return _bottlesInStock > 0; } @@ -210,10 +263,10 @@ namespace UVtools.Core.Objects /// Add print time with this material /// /// Seconds to add - public void AddPrintTime(double seconds) + public void AddPrintTimeSeconds(double seconds) { if (seconds <= 0) return; - TotalPrintTime += seconds / 60 / 60; + PrintTime += seconds / 60 / 60; } #endregion } diff --git a/UVtools.Core/Operations/OperationIPrintedThisFile.cs b/UVtools.Core/Operations/OperationIPrintedThisFile.cs new file mode 100644 index 0000000..851c4d1 --- /dev/null +++ b/UVtools.Core/Operations/OperationIPrintedThisFile.cs @@ -0,0 +1,138 @@ +/* + * GNU AFFERO GENERAL PUBLIC LICENSE + * Version 3, 19 November 2007 + * Copyright (C) 2007 Free Software Foundation, Inc. + * Everyone is permitted to copy and distribute verbatim copies + * of this license document, but changing it is not allowed. + */ + +using System; +using System.Text; +using UVtools.Core.FileFormats; +using UVtools.Core.Managers; +using UVtools.Core.Objects; + +namespace UVtools.Core.Operations +{ + [Serializable] + public class OperationIPrintedThisFile : Operation + { + #region Members + private decimal _volume; + private float _printTime; + private Material _materialItem; + + #endregion + + #region Overrides + + public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None; + + public override bool CanROI => false; + public override bool CanHaveProfiles => false; + public override string ButtonOkText => "Consume"; + + public override string Title => "I printed this file"; + public override string Description => "Select a material and consume resin from stock and print time."; + + public override string ConfirmationText => + $"consume {_volume}ml and {PrintTimeHours}h on:\n{_materialItem} ?"; + + public override string ProgressTitle => + $"Consuming"; + + public override string ProgressAction => "Consumed"; + + public override StringTag Validate(params object[] parameters) + { + var sb = new StringBuilder(); + + if (_materialItem is null) + { + sb.AppendLine("You must select an material."); + } + if (_volume <= 0) + { + sb.AppendLine("Volume must be higher than 0ml."); + } + if (_printTime <= 0) + { + sb.AppendLine("Print time must be higher than 0s."); + } + + return new StringTag(sb.ToString()); + } + + public override string ToString() + { + var result = $"{_volume}ml {PrintTimeHours}h"; + if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}"; + return result; + } + #endregion + + #region Properties + + public Material MaterialItem + { + get => _materialItem; + set => RaiseAndSetIfChanged(ref _materialItem, value); + } + + public decimal Volume + { + get => _volume; + set => RaiseAndSetIfChanged(ref _volume, value); + } + + public float PrintTime + { + get => _printTime; + set + { + if(!RaiseAndSetIfChanged(ref _printTime, value)) return; + RaisePropertyChanged(nameof(PrintTimeHours)); + } + } + + public float PrintTimeHours => _printTime / 60 / 60; + + public MaterialManager Manager => MaterialManager.Instance; + + #endregion + + #region Constructor + + public OperationIPrintedThisFile() { } + + public OperationIPrintedThisFile(FileFormat slicerFile) : base(slicerFile) { } + + public override void InitWithSlicerFile() + { + base.InitWithSlicerFile(); + _volume = (decimal) SlicerFile.MaterialMilliliters; + _printTime = SlicerFile.PrintTime; + MaterialManager.Load(); + } + + #endregion + + #region Methods + + protected override bool ExecuteInternally(OperationProgress progress) + { + if (MaterialItem is null) return !progress.Token.IsCancellationRequested; + + MaterialItem.Consume(_volume, _printTime); + + MaterialManager.Save(); + return !progress.Token.IsCancellationRequested; + } + + #endregion + + #region Equality + + #endregion + } +} diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index 37302e0..9c4fcf6 100644 --- a/UVtools.Core/UVtools.Core.csproj +++ b/UVtools.Core/UVtools.Core.csproj @@ -10,7 +10,7 @@ https://github.com/sn4k3/UVtools https://github.com/sn4k3/UVtools MSLA/DLP, file analysis, calibration, repair, conversion and manipulation - 2.4.9 + 2.5.0 Copyright © 2020 PTRTECH UVtools.png AnyCPU;x64 @@ -44,7 +44,7 @@ - + diff --git a/UVtools.WPF/App.axaml.cs b/UVtools.WPF/App.axaml.cs index 219a7db..7a454a1 100644 --- a/UVtools.WPF/App.axaml.cs +++ b/UVtools.WPF/App.axaml.cs @@ -22,6 +22,7 @@ using Avalonia.ThemeManager; using Emgu.CV; using UVtools.Core; using UVtools.Core.FileFormats; +using UVtools.Core.Managers; using UVtools.WPF.Extensions; using UVtools.WPF.Structures; @@ -52,6 +53,9 @@ namespace UVtools.WPF OperationProfiles.Load(); + MaterialManager.FilePath = Path.Combine(UserSettings.SettingsFolder, "materials.xml"); + MaterialManager.Load(); + /*ThemeSelector = ThemeSelector.Create(Path.Combine(ApplicationPath, "Assets", "Themes")); ThemeSelector.LoadSelectedTheme(Path.Combine(UserSettings.SettingsFolder, "selected.theme")); if (ThemeSelector.SelectedTheme.Name == "UVtoolsDark" || ThemeSelector.SelectedTheme.Name == "Light") diff --git a/UVtools.WPF/Assets/Icons/flask-16x16.png b/UVtools.WPF/Assets/Icons/flask-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..4cd3c0a29c72646ad465b7c98fbad5225491f8cb GIT binary patch literal 162 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6GCf@!Ln;`P8=C)T2ylJSJ`mEh zfPHyW)PfIe2HDILLc8^H&wh~R&^?&rZE#yE^dR4Yb!Hapc~9JK)QRO1Inc7yAXB-` zKSH#I>C^$4R_440jUOGs2i-fG7F&qQv}zQj?q~}A#TC%T$nZC|wy@oevk+)0gQu&X J%Q~loCIIPAHunGk literal 0 HcmV?d00001 diff --git a/UVtools.WPF/Controls/Tools/ToolIPrintedThisFileControl.axaml b/UVtools.WPF/Controls/Tools/ToolIPrintedThisFileControl.axaml new file mode 100644 index 0000000..7d2e04f --- /dev/null +++ b/UVtools.WPF/Controls/Tools/ToolIPrintedThisFileControl.axaml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UVtools.WPF/Controls/Tools/ToolIPrintedThisFileControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolIPrintedThisFileControl.axaml.cs new file mode 100644 index 0000000..91ed2f1 --- /dev/null +++ b/UVtools.WPF/Controls/Tools/ToolIPrintedThisFileControl.axaml.cs @@ -0,0 +1,21 @@ +using Avalonia.Markup.Xaml; +using UVtools.Core.Operations; + +namespace UVtools.WPF.Controls.Tools +{ + public class ToolIPrintedThisFileControl : ToolControl + { + public OperationIPrintedThisFile Operation => BaseOperation as OperationIPrintedThisFile; + + public ToolIPrintedThisFileControl() + { + InitializeComponent(); + BaseOperation = new OperationIPrintedThisFile(SlicerFile); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/UVtools.WPF/MainWindow.axaml b/UVtools.WPF/MainWindow.axaml index 93d132f..2229ca7 100644 --- a/UVtools.WPF/MainWindow.axaml +++ b/UVtools.WPF/MainWindow.axaml @@ -72,6 +72,15 @@ + + + + + + + + + + + + @@ -189,6 +208,8 @@ + + LICENSE https://github.com/sn4k3/UVtools Git - 2.4.9 + 2.5.0 @@ -75,4 +75,9 @@ + + + PrusaSlicerManagerWindow.axaml + + diff --git a/UVtools.WPF/Windows/MaterialManagerWindow.axaml b/UVtools.WPF/Windows/MaterialManagerWindow.axaml new file mode 100644 index 0000000..52908af --- /dev/null +++ b/UVtools.WPF/Windows/MaterialManagerWindow.axaml @@ -0,0 +1,254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UVtools.WPF/Windows/MaterialManagerWindow.axaml.cs b/UVtools.WPF/Windows/MaterialManagerWindow.axaml.cs new file mode 100644 index 0000000..a519d34 --- /dev/null +++ b/UVtools.WPF/Windows/MaterialManagerWindow.axaml.cs @@ -0,0 +1,97 @@ +using System; +using System.Linq; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using DynamicData; +using MessageBox.Avalonia.Enums; +using UVtools.Core.Managers; +using UVtools.Core.Objects; +using UVtools.WPF.Controls; +using UVtools.WPF.Extensions; + +namespace UVtools.WPF.Windows +{ + public class MaterialManagerWindow : WindowEx + { + private Material _material = new(); + private readonly DataGrid _grid; + public MaterialManager Manager => MaterialManager.Instance; + + public Material Material + { + get => _material; + set => RaiseAndSetIfChanged(ref _material, value); + } + + public MaterialManagerWindow() + { + InitializeComponent(); +#if DEBUG + this.AttachDevTools(); +#endif + + _grid = this.FindControl("MaterialsTable"); + + MaterialManager.Load(); // Reload + + DataContext = this; + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + + protected override void OnClosed(EventArgs e) + { + base.OnClosed(e); + MaterialManager.Save(); // Apply changes + } + + public void RefreshStatistics() + { + Manager.RaisePropertiesChanged(); + } + + public async void AddNewMaterial() + { + if (string.IsNullOrWhiteSpace(Material.Name)) + { + await this.MessageBoxError("Material name can't be empty"); + return; + } + + if (Manager.Contains(Material)) + { + await this.MessageBoxError("A material with same name already exists."); + return; + } + + Material.BottleRemainingVolume = Material.BottleVolume; + + if (await this.MessageBoxQuestion("Are you sure you want to add the following material:\n" + + $"{Material}") != ButtonResult.Yes) return; + + Manager.Add(Material); + Manager.SortByName(); + MaterialManager.Save(); + Material = new(); + } + + public async void RemoveSelectedMaterials() + { + if (_grid.SelectedItems.Count <= 0) return; + if (await this.MessageBoxQuestion($"Are you sure you want to remove {_grid.SelectedItems.Count} materials?") != ButtonResult.Yes) return; + Manager.RemoveMany(_grid.SelectedItems.Cast()); + MaterialManager.Save(); + } + + public async void ClearMaterials() + { + if (Manager.Count == 0) return; + if (await this.MessageBoxQuestion($"Are you sure you want to clear {Manager.Count} materials?") != ButtonResult.Yes) return; + Manager.Clear(true); + } + } +} diff --git a/UVtools.WPF/Windows/PrusaSlicerManager.axaml b/UVtools.WPF/Windows/PrusaSlicerManagerWindow.axaml similarity index 99% rename from UVtools.WPF/Windows/PrusaSlicerManager.axaml rename to UVtools.WPF/Windows/PrusaSlicerManagerWindow.axaml index e9d6b1c..72184b1 100644 --- a/UVtools.WPF/Windows/PrusaSlicerManager.axaml +++ b/UVtools.WPF/Windows/PrusaSlicerManagerWindow.axaml @@ -4,7 +4,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:controls="clr-namespace:UVtools.WPF.Controls" mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="700" - x:Class="UVtools.WPF.Windows.PrusaSlicerManager" + x:Class="UVtools.WPF.Windows.PrusaSlicerManagerWindow" Title="Install profiles into PrusaSlicer" Width="900" MinWidth="900" diff --git a/UVtools.WPF/Windows/PrusaSlicerManager.axaml.cs b/UVtools.WPF/Windows/PrusaSlicerManagerWindow.axaml.cs similarity index 96% rename from UVtools.WPF/Windows/PrusaSlicerManager.axaml.cs rename to UVtools.WPF/Windows/PrusaSlicerManagerWindow.axaml.cs index ae24b3c..4b30c9c 100644 --- a/UVtools.WPF/Windows/PrusaSlicerManager.axaml.cs +++ b/UVtools.WPF/Windows/PrusaSlicerManagerWindow.axaml.cs @@ -10,11 +10,11 @@ using UVtools.WPF.Structures; namespace UVtools.WPF.Windows { - public class PrusaSlicerManager : WindowEx + public class PrusaSlicerManagerWindow : WindowEx { public PEProfileFolder[] Profiles { get;} - public PrusaSlicerManager() + public PrusaSlicerManagerWindow() { InitializeComponent(); Profiles = new[]